Decompiled source of BigRockHero v0.5.1
plugins/Concentus.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using Concentus.Celt; using Concentus.Celt.Structs; using Concentus.Common; using Concentus.Common.CPlusPlus; using Concentus.Enums; using Concentus.Native; using Concentus.Silk; using Concentus.Silk.Enums; using Concentus.Silk.Structs; using Concentus.Structs; using Microsoft.CodeAnalysis; using Microsoft.Win32.SafeHandles; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("ParityTest, PublicKey=002400000480000094000000060200000024000052534131000400000100010071a2f675c04c87e64b9be6d37f5833c5285fb4ed883780cf6d61e80aee5d77950b2f06dd45bc634f53405f2a2b7b2332f4dfdcb0554ffc97b935e7343e76e733eea44346e56ac1098c12a66de71e324f2f503f9f2e32560910e2082d6943df50db42679a330e52979bd1eefbb59485d2c7420d158f6ab6d41bdf42d2172675e1")] [assembly: InternalsVisibleTo("TestOpusEncode, PublicKey=002400000480000094000000060200000024000052534131000400000100010071a2f675c04c87e64b9be6d37f5833c5285fb4ed883780cf6d61e80aee5d77950b2f06dd45bc634f53405f2a2b7b2332f4dfdcb0554ffc97b935e7343e76e733eea44346e56ac1098c12a66de71e324f2f503f9f2e32560910e2082d6943df50db42679a330e52979bd1eefbb59485d2c7420d158f6ab6d41bdf42d2172675e1")] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Logan Stromberg")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("© Xiph.Org Foundation, Skype Limited, CSIRO, Microsoft Corp.")] [assembly: AssemblyDescription("This package is a portable C# implementation of the Opus audio compression codec (see https://opus-codec.org/ for more details). This package contains the Opus encoder, decoder, multistream codecs, repacketizer, as well as a port of the libspeexdsp resampler. It does NOT contain code to parse .ogg or .opus container files or to manage RTP packet streams. For better performance depending on your platform, see also the Concentus.Native package.")] [assembly: AssemblyFileVersion("2.2.2.0")] [assembly: AssemblyInformationalVersion("2.2.2+6c2328dc19044601e33a9c11628b8d60e1f3011c")] [assembly: AssemblyProduct("Concentus")] [assembly: AssemblyTitle("Concentus")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/lostromb/concentus")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.2.2.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } } namespace Concentus { public interface IOpusDecoder : IDisposable { OpusBandwidth Bandwidth { get; } uint FinalRange { get; } int Gain { get; set; } int LastPacketDuration { get; } int NumChannels { get; } int Pitch { get; } int SampleRate { get; } int Decode(ReadOnlySpan<byte> in_data, Span<float> out_pcm, int frame_size, bool decode_fec = false); int Decode(ReadOnlySpan<byte> in_data, Span<short> out_pcm, int frame_size, bool decode_fec = false); void ResetState(); string GetVersionString(); } public interface IOpusEncoder : IDisposable { OpusApplication Application { get; set; } int Bitrate { get; set; } int ForceChannels { get; set; } OpusBandwidth MaxBandwidth { get; set; } OpusBandwidth Bandwidth { get; set; } bool UseDTX { get; set; } int Complexity { get; set; } bool UseInbandFEC { get; set; } int PacketLossPercent { get; set; } bool UseVBR { get; set; } bool UseConstrainedVBR { get; set; } OpusSignal SignalType { get; set; } int Lookahead { get; } int SampleRate { get; } int NumChannels { get; } uint FinalRange { get; } int LSBDepth { get; set; } OpusFramesize ExpertFrameDuration { get; set; } OpusMode ForceMode { set; } bool PredictionDisabled { get; set; } int Encode(ReadOnlySpan<short> in_pcm, int frame_size, Span<byte> out_data, int max_data_bytes); int Encode(ReadOnlySpan<float> in_pcm, int frame_size, Span<byte> out_data, int max_data_bytes); void ResetState(); string GetVersionString(); } public interface IOpusMultiStreamDecoder : IDisposable { OpusBandwidth Bandwidth { get; } uint FinalRange { get; } int Gain { get; set; } int LastPacketDuration { get; } int SampleRate { get; } int NumChannels { get; } int DecodeMultistream(ReadOnlySpan<byte> data, Span<float> out_pcm, int frame_size, bool decode_fec); int DecodeMultistream(ReadOnlySpan<byte> data, Span<short> out_pcm, int frame_size, bool decode_fec); void ResetState(); string GetVersionString(); } public interface IOpusMultiStreamEncoder : IDisposable { OpusApplication Application { get; set; } OpusBandwidth Bandwidth { get; set; } int Bitrate { get; set; } int Complexity { get; set; } int NumChannels { get; } OpusFramesize ExpertFrameDuration { get; set; } uint FinalRange { get; } OpusMode ForceMode { set; } int Lookahead { get; } int LSBDepth { get; set; } OpusBandwidth MaxBandwidth { get; set; } int PacketLossPercent { get; set; } bool PredictionDisabled { get; set; } int SampleRate { get; } OpusSignal SignalType { get; set; } bool UseConstrainedVBR { get; set; } bool UseDTX { get; set; } bool UseInbandFEC { get; set; } bool UseVBR { get; set; } int EncodeMultistream(ReadOnlySpan<float> in_pcm, int frame_size, Span<byte> out_data, int max_data_bytes); int EncodeMultistream(ReadOnlySpan<short> in_pcm, int frame_size, Span<byte> out_data, int max_data_bytes); void ResetState(); string GetVersionString(); } public interface IResampler : IDisposable { int InputLatency { get; } int InputStride { get; set; } int OutputLatencySamples { get; } TimeSpan OutputLatency { get; } int OutputStride { get; set; } int Quality { get; set; } void GetRateFraction(out int ratio_num, out int ratio_den); void GetRates(out int in_rate, out int out_rate); void ResetMem(); void SkipZeroes(); void Process(int channel_index, Span<float> input, ref int in_len, Span<float> output, ref int out_len); void Process(int channel_index, Span<short> input, ref int in_len, Span<short> output, ref int out_len); void ProcessInterleaved(Span<float> input, ref int in_len, Span<float> output, ref int out_len); void ProcessInterleaved(Span<short> input, ref int in_len, Span<short> output, ref int out_len); void SetRateFraction(int ratio_num, int ratio_den, int in_rate, int out_rate); void SetRates(int in_rate, int out_rate); } public static class OpusCodecFactory { private static readonly object _mutex = new object(); private static bool _nativeLibInitialized = false; private static bool _isNativeLibAvailable = false; private static bool _userAllowNativeLib = true; public static bool AttemptToUseNativeLibrary { get { return _userAllowNativeLib; } set { _userAllowNativeLib = value; } } public static IOpusEncoder CreateEncoder(int sampleRate, int numChannels, OpusApplication application = OpusApplication.OPUS_APPLICATION_AUDIO, TextWriter messageLogger = null) { if (_userAllowNativeLib && NativeLibraryAvailable(messageLogger)) { return NativeOpusEncoder.Create(sampleRate, numChannels, application); } return new OpusEncoder(sampleRate, numChannels, application); } public static IOpusDecoder CreateDecoder(int sampleRate, int numChannels, TextWriter messageLogger = null) { if (_userAllowNativeLib && NativeLibraryAvailable(messageLogger)) { return NativeOpusDecoder.Create(sampleRate, numChannels); } return new OpusDecoder(sampleRate, numChannels); } public static IOpusMultiStreamEncoder CreateMultiStreamEncoder(int sampleRate, int numChannels, int mappingFamily, out int streams, out int coupledStreams, byte[] mapping, OpusApplication application, TextWriter messageLogger = null) { if (_userAllowNativeLib && NativeLibraryAvailable(messageLogger)) { return NativeOpusMultistreamEncoder.Create(sampleRate, numChannels, mappingFamily, out streams, out coupledStreams, mapping, application); } return OpusMSEncoder.CreateSurround(sampleRate, numChannels, mappingFamily, out streams, out coupledStreams, mapping, application); } public static IOpusMultiStreamDecoder CreateMultiStreamDecoder(int sampleRate, int numChannels, int streams, int coupledStreams, byte[] mapping, TextWriter messageLogger = null) { if (_userAllowNativeLib && NativeLibraryAvailable(messageLogger)) { return NativeOpusMultistreamDecoder.Create(sampleRate, numChannels, streams, coupledStreams, mapping); } return new OpusMSDecoder(sampleRate, numChannels, streams, coupledStreams, mapping); } private static bool NativeLibraryAvailable(TextWriter messageLogger) { lock (_mutex) { if (!_nativeLibInitialized) { try { _isNativeLibAvailable = NativeOpus.Initialize(messageLogger); messageLogger?.WriteLine($"Is native opus available? {_isNativeLibAvailable}"); } catch (Exception ex) { messageLogger?.WriteLine(ex.ToString()); } _nativeLibInitialized = true; } return _isNativeLibAvailable; } } } internal static class Analysis { private const double M_PI = 3.141592653; private const float cA = 0.43157974f; private const float cB = 0.678484f; private const float cC = 0.08595542f; private const float cE = MathF.PI / 2f; private const int NB_TONAL_SKIP_BANDS = 9; internal static float fast_atan2f(float y, float x) { if (Inlines.ABS16(x) + Inlines.ABS16(y) < 1E-09f) { x *= 1E+12f; y *= 1E+12f; } float num = x * x; float num2 = y * y; if (num < num2) { float num3 = (num2 + 0.678484f * num) * (num2 + 0.08595542f * num); if (num3 != 0f) { return (0f - x) * y * (num2 + 0.43157974f * num) / num3 + ((y < 0f) ? (-MathF.PI / 2f) : (MathF.PI / 2f)); } if (!(y < 0f)) { return MathF.PI / 2f; } return -MathF.PI / 2f; } float num4 = (num + 0.678484f * num2) * (num + 0.08595542f * num2); if (num4 != 0f) { return x * y * (num + 0.43157974f * num2) / num4 + ((y < 0f) ? (-MathF.PI / 2f) : (MathF.PI / 2f)) - ((x * y < 0f) ? (-MathF.PI / 2f) : (MathF.PI / 2f)); } return ((y < 0f) ? (-MathF.PI / 2f) : (MathF.PI / 2f)) - ((x * y < 0f) ? (-MathF.PI / 2f) : (MathF.PI / 2f)); } internal static void tonality_analysis_init(TonalityAnalysisState tonal) { tonal.Reset(); } internal static void tonality_get_info(TonalityAnalysisState tonal, AnalysisInfo info_out, int len) { int num = tonal.read_pos; int num2 = tonal.write_pos - tonal.read_pos; if (num2 < 0) { num2 += 200; } if (len > 480 && num != tonal.write_pos) { num++; if (num == 200) { num = 0; } } if (num == tonal.write_pos) { num--; } if (num < 0) { num = 199; } info_out.Assign(tonal.info[num]); tonal.read_subframe += len / 120; while (tonal.read_subframe >= 4) { tonal.read_subframe -= 4; tonal.read_pos++; } if (tonal.read_pos >= 200) { tonal.read_pos -= 200; } num2 = Inlines.IMAX(num2 - 10, 0); float num3 = 0f; int i; for (i = 0; i < 200 - num2; i++) { num3 += tonal.pmusic[i]; } for (; i < 200; i++) { num3 += tonal.pspeech[i]; } num3 = num3 * tonal.music_confidence + (1f - num3) * tonal.speech_confidence; info_out.music_prob = num3; } internal static void tonality_analysis<T>(TonalityAnalysisState tonal, CeltMode celt_mode, ReadOnlySpan<T> x, int len, int offset, int c1, int c2, int C, int lsb_depth, Downmix.downmix_func<T> downmix) { int num = 480; int num2 = 240; float[] angle = tonal.angle; float[] d_angle = tonal.d_angle; float[] d2_angle = tonal.d2_angle; float[] array = new float[18]; float[] array2 = new float[18]; float[] array3 = new float[8]; float[] array4 = new float[25]; float num3 = 97.40909f; float num4 = 0f; float[] array5 = new float[2]; int num5 = 0; float num6 = 0f; tonal.last_transition++; float num7 = 1f / (float)Inlines.IMIN(20, 1 + tonal.count); float num8 = 1f / (float)Inlines.IMIN(50, 1 + tonal.count); float num9 = 1f / (float)Inlines.IMIN(1000, 1 + tonal.count); if (tonal.count < 4) { tonal.music_prob = 0.5f; } FFTState st = celt_mode.mdct.kfft[0]; if (tonal.count == 0) { tonal.mem_fill = 240; } downmix(x, tonal.inmem, tonal.mem_fill, Inlines.IMIN(len, 720 - tonal.mem_fill), offset, c1, c2, C); if (tonal.mem_fill + len < 720) { tonal.mem_fill += len; return; } AnalysisInfo analysisInfo = tonal.info[tonal.write_pos++]; if (tonal.write_pos >= 200) { tonal.write_pos -= 200; } int[] array6 = new int[960]; int[] array7 = new int[960]; float[] array8 = new float[240]; float[] array9 = new float[240]; for (int i = 0; i < num2; i++) { float num10 = Tables.analysis_window[i]; array6[2 * i] = (int)(num10 * (float)tonal.inmem[i]); array6[2 * i + 1] = (int)(num10 * (float)tonal.inmem[num2 + i]); array6[2 * (num - i - 1)] = (int)(num10 * (float)tonal.inmem[num - i - 1]); array6[2 * (num - i - 1) + 1] = (int)(num10 * (float)tonal.inmem[num + num2 - i - 1]); } Arrays.MemMoveInt(tonal.inmem, 480, 0, 240); int num11 = len - (720 - tonal.mem_fill); downmix(x, tonal.inmem, 240, num11, offset + 720 - tonal.mem_fill, c1, c2, C); tonal.mem_fill = 240 + num11; KissFFT.opus_fft(st, array6, array7); for (int i = 1; i < num2; i++) { float x2 = (float)array7[2 * i] + (float)array7[2 * (num - i)]; float y = (float)array7[2 * i + 1] - (float)array7[2 * (num - i) + 1]; float x3 = (float)array7[2 * i + 1] + (float)array7[2 * (num - i) + 1]; float y2 = (float)array7[2 * (num - i)] - (float)array7[2 * i]; float num12 = 1f / (2f * MathF.PI) * fast_atan2f(y, x2); float num13 = num12 - angle[i]; float num14 = num13 - d_angle[i]; float num15 = 1f / (2f * MathF.PI) * fast_atan2f(y2, x3); float num16 = num15 - num12; float num17 = num16 - num13; float num18 = num14 - (float)Math.Floor(0.5f + num14); array9[i] = Inlines.ABS16(num18); num18 *= num18; num18 *= num18; float num19 = num17 - (float)Math.Floor(0.5f + num17); array9[i] += Inlines.ABS16(num19); num19 *= num19; num19 *= num19; float num20 = 0.25f * (d2_angle[i] + 2f * num18 + num19); array8[i] = 1f / (1f + 640f * num3 * num20) - 0.015f; angle[i] = num15; d_angle[i] = num16; d2_angle[i] = num19; } float num21 = 0f; float num22 = 0f; analysisInfo.activity = 0f; float num23 = 0f; float num24 = 0f; if (tonal.count == 0) { for (int j = 0; j < 18; j++) { tonal.lowE[j] = 1E+10f; tonal.highE[j] = -1E+10f; } } float num25 = 0f; float num26 = 0f; for (int j = 0; j < 18; j++) { float num27 = 0f; float num28 = 0f; float num29 = 0f; for (int i = Tables.tbands[j]; i < Tables.tbands[j + 1]; i++) { float num30 = (float)array7[2 * i] * (float)array7[2 * i] + (float)array7[2 * (num - i)] * (float)array7[2 * (num - i)] + (float)array7[2 * i + 1] * (float)array7[2 * i + 1] + (float)array7[2 * (num - i) + 1] * (float)array7[2 * (num - i) + 1]; num30 *= 5.55E-17f; num27 += num30; num28 += num30 * array8[i]; num29 += num30 * 2f * (0.5f - array9[i]); } tonal.E[tonal.E_count][j] = num27; num23 += num29 / (1E-15f + num27); num26 += (float)Math.Sqrt(num27 + 1E-10f); array2[j] = (float)Math.Log(num27 + 1E-10f); tonal.lowE[j] = Inlines.MIN32(array2[j], tonal.lowE[j] + 0.01f); tonal.highE[j] = Inlines.MAX32(array2[j], tonal.highE[j] - 0.1f); if (tonal.highE[j] < tonal.lowE[j] + 1f) { tonal.highE[j] += 0.5f; tonal.lowE[j] -= 0.5f; } num25 += (array2[j] - tonal.lowE[j]) / (1E-15f + tonal.highE[j] - tonal.lowE[j]); float num31; float num32 = (num31 = 0f); for (int i = 0; i < 8; i++) { num32 += (float)Math.Sqrt(tonal.E[i][j]); num31 += tonal.E[i][j]; } float num33 = Inlines.MIN16(0.99f, num32 / (float)Math.Sqrt(1E-15 + (double)(8f * num31))); num33 *= num33; num33 *= num33; num24 += num33; array[j] = Inlines.MAX16(num28 / (1E-15f + num27), num33 * tonal.prev_band_tonality[j]); num21 += array[j]; if (j >= 9) { num21 -= array[j - 18 + 9]; } num22 = Inlines.MAX16(num22, (1f + 0.03f * (float)(j - 18)) * num21); num4 += array[j] * (float)(j - 8); tonal.prev_band_tonality[j] = array[j]; } float num34 = 0f; num5 = 0; num6 = 0f; float num35 = 0.00057f / (float)(1 << Inlines.IMAX(0, lsb_depth - 8)); num35 *= 134217730f; num35 *= num35; for (int j = 0; j < 21; j++) { float num36 = 0f; int num37 = Tables.extra_bands[j]; int num38 = Tables.extra_bands[j + 1]; for (int i = num37; i < num38; i++) { float num39 = (float)array7[2 * i] * (float)array7[2 * i] + (float)array7[2 * (num - i)] * (float)array7[2 * (num - i)] + (float)array7[2 * i + 1] * (float)array7[2 * i + 1] + (float)array7[2 * (num - i) + 1] * (float)array7[2 * (num - i) + 1]; num36 += num39; } num6 = Inlines.MAX32(num6, num36); tonal.meanE[j] = Inlines.MAX32((1f - num9) * tonal.meanE[j], num36); num36 = Inlines.MAX32(num36, tonal.meanE[j]); num34 = Inlines.MAX32(0.05f * num34, num36); if ((double)num36 > 0.1 * (double)num34 && num36 * 1E+09f > num6 && num36 > num35 * (float)(num38 - num37)) { num5 = j; } } if (tonal.count <= 2) { num5 = 20; } num26 = 20f * (float)Math.Log10(num26); tonal.Etracker = Inlines.MAX32(tonal.Etracker - 0.03f, num26); tonal.lowECount *= 1f - num8; if (num26 < tonal.Etracker - 30f) { tonal.lowECount += num8; } for (int i = 0; i < 8; i++) { float num40 = 0f; for (int j = 0; j < 16; j++) { num40 += Tables.dct_table[i * 16 + j] * array2[j]; } array3[i] = num40; } num24 /= 18f; num25 /= 18f; if (tonal.count < 10) { num25 = 0.5f; } num23 /= 18f; analysisInfo.activity = num23 + (1f - num23) * num25; num21 = num22 / 9f; num21 = (tonal.prev_tonality = Inlines.MAX16(num21, tonal.prev_tonality * 0.8f)); num4 /= 64f; analysisInfo.tonality_slope = num4; tonal.E_count = (tonal.E_count + 1) % 8; tonal.count++; analysisInfo.tonality = num21; for (int i = 0; i < 4; i++) { array4[i] = -0.12299f * (array3[i] + tonal.mem[i + 24]) + 0.49195f * (tonal.mem[i] + tonal.mem[i + 16]) + 0.69693f * tonal.mem[i + 8] - 1.4349f * tonal.cmean[i]; } for (int i = 0; i < 4; i++) { tonal.cmean[i] = (1f - num7) * tonal.cmean[i] + num7 * array3[i]; } for (int i = 0; i < 4; i++) { array4[4 + i] = 0.63246f * (array3[i] - tonal.mem[i + 24]) + 0.31623f * (tonal.mem[i] - tonal.mem[i + 16]); } for (int i = 0; i < 3; i++) { array4[8 + i] = 0.53452f * (array3[i] + tonal.mem[i + 24]) - 0.26726f * (tonal.mem[i] + tonal.mem[i + 16]) - 0.53452f * tonal.mem[i + 8]; } if (tonal.count > 5) { for (int i = 0; i < 9; i++) { tonal.std[i] = (1f - num7) * tonal.std[i] + num7 * array4[i] * array4[i]; } } for (int i = 0; i < 8; i++) { tonal.mem[i + 24] = tonal.mem[i + 16]; tonal.mem[i + 16] = tonal.mem[i + 8]; tonal.mem[i + 8] = tonal.mem[i]; tonal.mem[i] = array3[i]; } for (int i = 0; i < 9; i++) { array4[11 + i] = (float)Math.Sqrt(tonal.std[i]); } array4[20] = analysisInfo.tonality; array4[21] = analysisInfo.activity; array4[22] = num24; array4[23] = analysisInfo.tonality_slope; array4[24] = tonal.lowECount; MultiLayerPerceptron.mlp_process(Tables.net, array4, array5); array5[0] = 0.5f * (array5[0] + 1f); array5[0] = 0.01f + 1.21f * array5[0] * array5[0] - 0.23f * (float)Math.Pow(array5[0], 10.0); array5[1] = 0.5f * array5[1] + 0.5f; array5[0] = array5[1] * array5[0] + (1f - array5[1]) * 0.5f; float num41 = 5E-05f * array5[1]; float num42 = 0.05f; float num43 = Inlines.MAX16(0.05f, Inlines.MIN16(0.95f, array5[0])); float num44 = Inlines.MAX16(0.05f, Inlines.MIN16(0.95f, tonal.music_prob)); num42 = 0.01f + 0.05f * Inlines.ABS16(num43 - num44) / (num43 * (1f - num44) + num44 * (1f - num43)); float num45 = (1f - tonal.music_prob) * (1f - num41) + tonal.music_prob * num41; float num46 = tonal.music_prob * (1f - num41) + (1f - tonal.music_prob) * num41; num45 *= (float)Math.Pow(1f - array5[0], num42); num46 *= (float)Math.Pow(array5[0], num42); tonal.music_prob = num46 / (num45 + num46); analysisInfo.music_prob = tonal.music_prob; float num47 = 1E-20f; float num48 = (float)Math.Pow(1f - array5[0], num42); float num49 = (float)Math.Pow(array5[0], num42); if (tonal.count == 1) { tonal.pspeech[0] = 0.5f; tonal.pmusic[0] = 0.5f; } float num50 = tonal.pspeech[0] + tonal.pspeech[1]; float num51 = tonal.pmusic[0] + tonal.pmusic[1]; tonal.pspeech[0] = num50 * (1f - num41) * num48; tonal.pmusic[0] = num51 * (1f - num41) * num49; for (int i = 1; i < 199; i++) { tonal.pspeech[i] = tonal.pspeech[i + 1] * num48; tonal.pmusic[i] = tonal.pmusic[i + 1] * num49; } tonal.pspeech[199] = num51 * num41 * num48; tonal.pmusic[199] = num50 * num41 * num49; for (int i = 0; i < 200; i++) { num47 += tonal.pspeech[i] + tonal.pmusic[i]; } num47 = 1f / num47; for (int i = 0; i < 200; i++) { tonal.pspeech[i] *= num47; tonal.pmusic[i] *= num47; } num47 = tonal.pmusic[0]; for (int i = 1; i < 200; i++) { num47 += tonal.pspeech[i]; } if ((double)array5[1] > 0.75) { if ((double)tonal.music_prob > 0.9) { float num52 = 1f / (float)(++tonal.music_confidence_count); tonal.music_confidence_count = Inlines.IMIN(tonal.music_confidence_count, 500); tonal.music_confidence += num52 * Inlines.MAX16(-0.2f, array5[0] - tonal.music_confidence); } if ((double)tonal.music_prob < 0.1) { float num53 = 1f / (float)(++tonal.speech_confidence_count); tonal.speech_confidence_count = Inlines.IMIN(tonal.speech_confidence_count, 500); tonal.speech_confidence += num53 * Inlines.MIN16(0.2f, array5[0] - tonal.speech_confidence); } } else { if (tonal.music_confidence_count == 0) { tonal.music_confidence = 0.9f; } if (tonal.speech_confidence_count == 0) { tonal.speech_confidence = 0.1f; } } if (tonal.last_music != ((tonal.music_prob > 0.5f) ? 1 : 0)) { tonal.last_transition = 0; } tonal.last_music = ((tonal.music_prob > 0.5f) ? 1 : 0); analysisInfo.bandwidth = num5; analysisInfo.noisiness = num23; analysisInfo.valid = 1; } internal static void run_analysis<T>(TonalityAnalysisState analysis, CeltMode celt_mode, ReadOnlySpan<T> analysis_pcm, int analysis_frame_size, int frame_size, int c1, int c2, int C, int Fs, int lsb_depth, Downmix.downmix_func<T> downmix, AnalysisInfo analysis_info) { if (!analysis_pcm.IsEmpty) { analysis_frame_size = Inlines.IMIN(195 * Fs / 100, analysis_frame_size); int num = analysis_frame_size - analysis.analysis_offset; int num2 = analysis.analysis_offset; do { tonality_analysis(analysis, celt_mode, analysis_pcm, Inlines.IMIN(480, num), num2, c1, c2, C, lsb_depth, downmix); num2 += 480; num -= 480; } while (num > 0); analysis.analysis_offset = analysis_frame_size; analysis.analysis_offset -= frame_size; } analysis_info.valid = 0; tonality_get_info(analysis, analysis_info, frame_size); } } internal static class CodecHelpers { private const int MAX_DYNAMIC_FRAMESIZE = 24; internal static byte gen_toc(OpusMode mode, int framerate, OpusBandwidth bandwidth, int channels) { int num = 0; while (framerate < 400) { framerate <<= 1; num++; } byte b; switch (mode) { case OpusMode.MODE_SILK_ONLY: b = (byte)((int)(bandwidth - 1101) << 5); b |= (byte)(num - 2 << 3); break; case OpusMode.MODE_CELT_ONLY: { int num2 = (int)(bandwidth - 1102); if (num2 < 0) { num2 = 0; } b = 128; b |= (byte)(num2 << 5); b |= (byte)(num << 3); break; } default: b = 96; b |= (byte)((int)(bandwidth - 1104) << 4); b |= (byte)(num - 2 << 3); break; } return (byte)(b | (byte)(((channels == 2) ? 1u : 0u) << 2)); } internal static void hp_cutoff(ReadOnlySpan<short> input, int input_ptr, int cutoff_Hz, Span<short> output, int output_ptr, int[] hp_mem, int len, int channels, int Fs) { int[] array = new int[3]; int[] array2 = new int[2]; int num = Inlines.silk_DIV32_16(Inlines.silk_SMULBB(2471, cutoff_Hz), Fs / 1000); int num2 = (array[0] = 268435456 - Inlines.silk_MUL(471, num)); array[1] = Inlines.silk_LSHIFT(-num2, 1); array[2] = num2; int num3 = Inlines.silk_RSHIFT(num2, 6); array2[0] = Inlines.silk_SMULWW(num3, Inlines.silk_SMULWW(num, num) - 8388608); array2[1] = Inlines.silk_SMULWW(num3, num3); Filters.silk_biquad_alt(input, input_ptr, array, array2, hp_mem, 0, output, output_ptr, len, channels); if (channels == 2) { Filters.silk_biquad_alt(input, input_ptr + 1, array, array2, hp_mem, 2, output, output_ptr + 1, len, channels); } } internal static void dc_reject(ReadOnlySpan<short> input, int input_ptr, int cutoff_Hz, Span<short> output, int output_ptr, int[] hp_mem, int len, int channels, int Fs) { int shift = Inlines.celt_ilog2(Fs / (cutoff_Hz * 3)); for (int i = 0; i < channels; i++) { for (int j = 0; j < len; j++) { int num = Inlines.SHL32(Inlines.EXTEND32(input[channels * j + i + input_ptr]), 15); int num2 = num - hp_mem[2 * i]; hp_mem[2 * i] += Inlines.PSHR32(num - hp_mem[2 * i], shift); int a = num2 - hp_mem[2 * i + 1]; hp_mem[2 * i + 1] += Inlines.PSHR32(num2 - hp_mem[2 * i + 1], shift); output[channels * j + i + output_ptr] = Inlines.EXTRACT16(Inlines.SATURATE(Inlines.PSHR32(a, 15), 32767)); } } } internal static void stereo_fade(short[] pcm_buf, int g1, int g2, int overlap48, int frame_size, int channels, int[] window, int Fs) { int num = 48000 / Fs; int num2 = overlap48 / num; g1 = 32767 - g1; g2 = 32767 - g2; int i; for (i = 0; i < num2; i++) { int num3 = Inlines.MULT16_16_Q15(window[i * num], window[i * num]); int a = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(num3, g2), 32767 - num3, g1), 15); int b = Inlines.EXTRACT16(Inlines.HALF32(pcm_buf[i * channels] - pcm_buf[i * channels + 1])); b = Inlines.MULT16_16_Q15(a, b); pcm_buf[i * channels] = (short)(pcm_buf[i * channels] - b); pcm_buf[i * channels + 1] = (short)(pcm_buf[i * channels + 1] + b); } for (; i < frame_size; i++) { int b2 = Inlines.EXTRACT16(Inlines.HALF32(pcm_buf[i * channels] - pcm_buf[i * channels + 1])); b2 = Inlines.MULT16_16_Q15(g2, b2); pcm_buf[i * channels] = (short)(pcm_buf[i * channels] - b2); pcm_buf[i * channels + 1] = (short)(pcm_buf[i * channels + 1] + b2); } } internal static void gain_fade(short[] buffer, int buf_ptr, int g1, int g2, int overlap48, int frame_size, int channels, int[] window, int Fs) { int num = 48000 / Fs; int num2 = overlap48 / num; if (channels == 1) { for (int i = 0; i < num2; i++) { int num3 = Inlines.MULT16_16_Q15(window[i * num], window[i * num]); int a = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(num3, g2), 32767 - num3, g1), 15); buffer[buf_ptr + i] = (short)Inlines.MULT16_16_Q15(a, buffer[buf_ptr + i]); } } else { for (int i = 0; i < num2; i++) { int num4 = Inlines.MULT16_16_Q15(window[i * num], window[i * num]); int a2 = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(num4, g2), 32767 - num4, g1), 15); buffer[buf_ptr + i * 2] = (short)Inlines.MULT16_16_Q15(a2, buffer[buf_ptr + i * 2]); buffer[buf_ptr + i * 2 + 1] = (short)Inlines.MULT16_16_Q15(a2, buffer[buf_ptr + i * 2 + 1]); } } int num5 = 0; do { for (int i = num2; i < frame_size; i++) { buffer[buf_ptr + i * channels + num5] = (short)Inlines.MULT16_16_Q15(g2, buffer[buf_ptr + i * channels + num5]); } } while (++num5 < channels); } internal static float transient_boost(Span<float> E, int E_ptr, float[] E_1, int LM, int maxM) { float num = 0f; float num2 = 0f; int num3 = Inlines.IMIN(maxM, (1 << LM) + 1); for (int i = E_ptr; i < num3 + E_ptr; i++) { num += E[i]; num2 += E_1[i]; } float num4 = num * num2 / (float)(num3 * num3); return Inlines.MIN16(1f, (float)Math.Sqrt(Inlines.MAX16(0f, 0.05f * (num4 - 2f)))); } internal static int transient_viterbi(float[] E, float[] E_1, int N, int frame_cost, int rate) { float[][] array = Arrays.InitTwoDimensionalArray<float>(24, 16); int[][] array2 = Arrays.InitTwoDimensionalArray<int>(24, 16); float num = ((rate < 80) ? 0f : ((rate <= 160) ? (((float)rate - 80f) / 80f) : 1f)); for (int i = 0; i < 16; i++) { array2[0][i] = -1; array[0][i] = 1E+10f; } for (int i = 0; i < 4; i++) { array[0][1 << i] = (float)(frame_cost + rate * (1 << i)) * (1f + num * transient_boost(E, 0, E_1, i, N + 1)); array2[0][1 << i] = i; } for (int i = 1; i < N; i++) { for (int j = 2; j < 16; j++) { array[i][j] = array[i - 1][j - 1]; array2[i][j] = j - 1; } for (int j = 0; j < 4; j++) { array2[i][1 << j] = 1; float num2 = array[i - 1][1]; for (int k = 1; k < 4; k++) { float num3 = array[i - 1][(1 << k + 1) - 1]; if (num3 < num2) { array2[i][1 << j] = (1 << k + 1) - 1; num2 = num3; } } float num4 = (float)(frame_cost + rate * (1 << j)) * (1f + num * transient_boost(E, i, E_1, j, N - i + 1)); array[i][1 << j] = num2; if (N - i < 1 << j) { array[i][1 << j] += num4 * (float)(N - i) / (float)(1 << j); } else { array[i][1 << j] += num4; } } } int num5 = 1; float num6 = array[N - 1][1]; for (int i = 2; i < 16; i++) { if (array[N - 1][i] < num6) { num6 = array[N - 1][i]; num5 = i; } } for (int i = N - 1; i >= 0; i--) { num5 = array2[i][num5]; } return num5; } internal static int optimize_framesize<T>(ReadOnlySpan<T> x, int len, int C, int Fs, int bitrate, int tonality, float[] mem, int buffering, Downmix.downmix_func<T> downmix) { float[] array = new float[28]; float[] array2 = new float[27]; int num = 0; int num2 = Fs / 400; int[] array3 = new int[num2]; array[0] = mem[0]; array2[0] = 1f / (1f + mem[0]); int num3; int num4; if (buffering != 0) { num3 = 2 * num2 - buffering; len -= num3; array[1] = mem[1]; array2[1] = 1f / (1f + mem[1]); array[2] = mem[2]; array2[2] = 1f / (1f + mem[2]); num4 = 3; } else { num4 = 1; num3 = 0; } int num5 = Inlines.IMIN(len / num2, 24); int num6 = 0; int i; for (i = 0; i < num5; i++) { float num7 = 1f; downmix(x, array3, 0, num2, i * num2 + num3, 0, -2, C); if (i == 0) { num6 = array3[0]; } for (int j = 0; j < num2; j++) { int num8 = array3[j]; num7 += (float)(num8 - num6) * (float)(num8 - num6); num6 = num8; } array[i + num4] = num7; array2[i + num4] = 1f / num7; } array[i + num4] = array[i + num4 - 1]; if (buffering != 0) { num5 = Inlines.IMIN(24, num5 + 2); } num = transient_viterbi(array, array2, num5, (int)((1f + 0.5f * (float)tonality) * (float)(60 * C + 40)), bitrate / 400); mem[0] = array[1 << num]; if (buffering != 0) { mem[1] = array[(1 << num) + 1]; mem[2] = array[(1 << num) + 2]; } return num; } internal static int frame_size_select(int frame_size, OpusFramesize variable_duration, int Fs) { if (frame_size < Fs / 400) { return -1; } int num; switch (variable_duration) { case OpusFramesize.OPUS_FRAMESIZE_ARG: num = frame_size; break; case OpusFramesize.OPUS_FRAMESIZE_VARIABLE: num = Fs / 50; break; case OpusFramesize.OPUS_FRAMESIZE_2_5_MS: case OpusFramesize.OPUS_FRAMESIZE_5_MS: case OpusFramesize.OPUS_FRAMESIZE_10_MS: case OpusFramesize.OPUS_FRAMESIZE_20_MS: case OpusFramesize.OPUS_FRAMESIZE_40_MS: case OpusFramesize.OPUS_FRAMESIZE_60_MS: num = Inlines.IMIN(3 * Fs / 50, Fs / 400 << (int)(variable_duration - 5001)); break; default: return -1; } if (num > frame_size) { return -1; } if (400 * num != Fs && 200 * num != Fs && 100 * num != Fs && 50 * num != Fs && 25 * num != Fs && 50 * num != 3 * Fs) { return -1; } return num; } internal static int compute_frame_size<T>(ReadOnlySpan<T> analysis_pcm, int frame_size, OpusFramesize variable_duration, int C, int Fs, int bitrate_bps, int delay_compensation, Downmix.downmix_func<T> downmix, float[] subframe_mem, bool analysis_enabled) { if (analysis_enabled && variable_duration == OpusFramesize.OPUS_FRAMESIZE_VARIABLE && frame_size >= Fs / 200) { int num = 3; num = optimize_framesize(analysis_pcm, frame_size, C, Fs, bitrate_bps, 0, subframe_mem, delay_compensation, downmix); while (Fs / 400 << num > frame_size) { num--; } frame_size = Fs / 400 << num; } else { frame_size = frame_size_select(frame_size, variable_duration, Fs); } if (frame_size < 0) { return -1; } return frame_size; } internal static int compute_stereo_width(ReadOnlySpan<short> pcm, int pcm_ptr, int frame_size, int Fs, StereoWidthState mem) { int num = Fs / frame_size; int a = 32767 - 819175 / Inlines.IMAX(50, num); int num3; int num2; int num4 = (num3 = (num2 = 0)); for (int i = 0; i < frame_size - 3; i += 4) { int num5 = 0; int num6 = 0; int num7 = 0; int num8 = pcm_ptr + 2 * i; int num9 = pcm[num8]; int num10 = pcm[num8 + 1]; num5 = Inlines.SHR32(Inlines.MULT16_16(num9, num9), 2); num6 = Inlines.SHR32(Inlines.MULT16_16(num9, num10), 2); num7 = Inlines.SHR32(Inlines.MULT16_16(num10, num10), 2); num9 = pcm[num8 + 2]; num10 = pcm[num8 + 3]; num5 += Inlines.SHR32(Inlines.MULT16_16(num9, num9), 2); num6 += Inlines.SHR32(Inlines.MULT16_16(num9, num10), 2); num7 += Inlines.SHR32(Inlines.MULT16_16(num10, num10), 2); num9 = pcm[num8 + 4]; num10 = pcm[num8 + 5]; num5 += Inlines.SHR32(Inlines.MULT16_16(num9, num9), 2); num6 += Inlines.SHR32(Inlines.MULT16_16(num9, num10), 2); num7 += Inlines.SHR32(Inlines.MULT16_16(num10, num10), 2); num9 = pcm[num8 + 6]; num10 = pcm[num8 + 7]; num5 += Inlines.SHR32(Inlines.MULT16_16(num9, num9), 2); num6 += Inlines.SHR32(Inlines.MULT16_16(num9, num10), 2); num7 += Inlines.SHR32(Inlines.MULT16_16(num10, num10), 2); num4 += Inlines.SHR32(num5, 10); num3 += Inlines.SHR32(num6, 10); num2 += Inlines.SHR32(num7, 10); } mem.XX += Inlines.MULT16_32_Q15(a, num4 - mem.XX); mem.XY += Inlines.MULT16_32_Q15(a, num3 - mem.XY); mem.YY += Inlines.MULT16_32_Q15(a, num2 - mem.YY); mem.XX = Inlines.MAX32(0, mem.XX); mem.XY = Inlines.MAX32(0, mem.XY); mem.YY = Inlines.MAX32(0, mem.YY); if (Inlines.MAX32(mem.XX, mem.YY) > 210) { int num11 = Inlines.celt_sqrt(mem.XX); int num12 = Inlines.celt_sqrt(mem.YY); int num13 = Inlines.celt_sqrt(num11); int num14 = Inlines.celt_sqrt(num12); mem.XY = Inlines.MIN32(mem.XY, num11 * num12); int num15 = Inlines.SHR32(Inlines.frac_div32(mem.XY, 1 + Inlines.MULT16_16(num11, num12)), 16); int b = 32767 * Inlines.ABS16(num13 - num14) / (1 + num13 + num14); int num16 = Inlines.MULT16_16_Q15(Inlines.celt_sqrt(1073741824 - Inlines.MULT16_16(num15, num15)), b); mem.smoothed_width += (num16 - mem.smoothed_width) / num; mem.max_follower = Inlines.MAX16(mem.max_follower - 655 / num, mem.smoothed_width); } else { int num16 = 0; int num15 = 32767; int b = 0; } return Inlines.EXTRACT16(Inlines.MIN32(32767, 20 * mem.max_follower)); } internal static void smooth_fade(Span<short> in1, int in1_ptr, Span<short> in2, int in2_ptr, Span<short> output, int output_ptr, int overlap, int channels, int[] window, int Fs) { int num = 48000 / Fs; for (int i = 0; i < channels; i++) { for (int j = 0; j < overlap; j++) { int num2 = Inlines.MULT16_16_Q15(window[j * num], window[j * num]); output[output_ptr + j * channels + i] = (short)Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(num2, in2[in2_ptr + j * channels + i]), 32767 - num2, in1[in1_ptr + j * channels + i]), 15); } } } internal static string opus_strerror(int error) { string[] array = new string[8] { "success", "invalid argument", "buffer too small", "internal error", "corrupted stream", "request not implemented", "invalid state", "memory allocation failed" }; if (error > 0 || error < -7) { return "unknown error"; } return array[-error]; } internal static string GetVersionString() { return "Concentus 2.1.2"; } } internal static class Downmix { internal delegate void downmix_func<T>(ReadOnlySpan<T> _x, Span<int> sub, int sub_ptr, int subframe, int offset, int c1, int c2, int C); internal static void downmix_float(ReadOnlySpan<float> x, Span<int> sub, int sub_ptr, int subframe, int offset, int c1, int c2, int C) { for (int i = 0; i < subframe; i++) { sub[sub_ptr + i] = Inlines.FLOAT2INT16(x[(i + offset) * C + c1]); } if (c2 > -1) { for (int i = 0; i < subframe; i++) { sub[sub_ptr + i] += Inlines.FLOAT2INT16(x[(i + offset) * C + c2]); } } else if (c2 == -2) { for (int j = 1; j < C; j++) { int num = j; for (int i = 0; i < subframe; i++) { sub[sub_ptr + i] += Inlines.FLOAT2INT16(x[(i + offset) * C + num]); } } } int num2 = 4096; num2 = ((C != -2) ? (num2 / 2) : (num2 / C)); for (int i = 0; i < subframe; i++) { sub[sub_ptr + i] *= num2; } } internal static void downmix_int(ReadOnlySpan<short> x, Span<int> sub, int sub_ptr, int subframe, int offset, int c1, int c2, int C) { for (int i = 0; i < subframe; i++) { sub[i + sub_ptr] = x[(i + offset) * C + c1]; } if (c2 > -1) { for (int i = 0; i < subframe; i++) { sub[i + sub_ptr] += x[(i + offset) * C + c2]; } } else if (c2 == -2) { for (int j = 1; j < C; j++) { for (int i = 0; i < subframe; i++) { sub[i + sub_ptr] += x[(i + offset) * C + j]; } } } int num = 4096; num = ((C != -2) ? (num / 2) : (num / C)); for (int i = 0; i < subframe; i++) { sub[i + sub_ptr] *= num; } } } internal static class MultiLayerPerceptron { private const int MAX_NEURONS = 100; internal static float tansig_approx(float x) { float num = 1f; if (!(x < 8f)) { return 1f; } if (!(x > -8f)) { return -1f; } if (x < 0f) { x = 0f - x; num = -1f; } int num2 = (int)Math.Floor(0.5f + 25f * x); x -= 0.04f * (float)num2; float num3 = Tables.tansig_table[num2]; float num4 = 1f - num3 * num3; num3 += x * num4 * (1f - num3 * x); return num * num3; } internal static void mlp_process(MLP m, float[] input, float[] output) { float[] array = new float[100]; float[] weights = m.weights; int num = 0; for (int i = 0; i < m.topo[1]; i++) { float num2 = weights[num]; num++; for (int j = 0; j < m.topo[0]; j++) { num2 += input[j] * weights[num]; num++; } array[i] = tansig_approx(num2); } for (int i = 0; i < m.topo[2]; i++) { float num3 = weights[num]; num++; for (int k = 0; k < m.topo[1]; k++) { num3 += array[k] * weights[num]; num++; } output[i] = tansig_approx(num3); } } } internal static class OpusCompare { private const int NBANDS = 21; private const int NFREQS = 240; private const int TEST_WIN_SIZE = 480; private const int TEST_WIN_STEP = 120; private static readonly int[] BANDS = new int[22] { 0, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120, 156, 200 }; private static void band_energy(Pointer<float> _out, Pointer<float> _ps, Pointer<int> _bands, int _nbands, Pointer<float> _in, int _nchannels, int _nframes, int _window_sz, int _step, int _downsample) { Pointer<float> pointer = Concentus.Common.CPlusPlus.Pointer.Malloc<float>((3 + _nchannels) * _window_sz); Pointer<float> pointer2 = pointer.Point(_window_sz); Pointer<float> pointer3 = pointer2.Point(_window_sz); Pointer<float> pointer4 = pointer3.Point(_window_sz); int num = _window_sz / 2; for (int i = 0; i < _window_sz; i++) { pointer[i] = (float)(0.5 - 0.5 * Math.Cos(Math.PI * 2.0 / (double)(_window_sz - 1) * (double)i)); } for (int i = 0; i < _window_sz; i++) { pointer2[i] = (float)Math.Cos(Math.PI * 2.0 / (double)_window_sz * (double)i); } for (int i = 0; i < _window_sz; i++) { pointer3[i] = (float)Math.Sin(Math.PI * 2.0 / (double)_window_sz * (double)i); } for (int j = 0; j < _nframes; j++) { for (int k = 0; k < _nchannels; k++) { for (int l = 0; l < _window_sz; l++) { pointer4[k * _window_sz + l] = pointer[l] * _in[(j * _step + l) * _nchannels + k]; } } int i; for (int m = (i = 0); m < _nbands; m++) { float[] array = new float[2]; for (; i < _bands[m + 1]; i++) { for (int k = 0; k < _nchannels; k++) { int num2 = 0; float num3; float num4 = (num3 = 0f); for (int l = 0; l < _window_sz; l++) { num4 += pointer2[num2] * pointer4[k * _window_sz + l]; num3 -= pointer3[num2] * pointer4[k * _window_sz + l]; num2 += i; if (num2 >= _window_sz) { num2 -= _window_sz; } } num4 *= (float)_downsample; num3 *= (float)_downsample; _ps[(j * num + i) * _nchannels + k] = num4 * num4 + num3 * num3 + 100000f; array[k] += _ps[(j * num + i) * _nchannels + k]; } } if (_out != null) { _out[(j * _nbands + m) * _nchannels] = array[0] / (float)(_bands[m + 1] - _bands[m]); if (_nchannels == 2) { _out[(j * _nbands + m) * _nchannels + 1] = array[1] / (float)(_bands[m + 1] - _bands[m]); } } } } } internal static float compare(float[] x, float[] y, int nchannels, int rate = 48000) { int num = x.Length; int num2 = y.Length; int num3 = 21; int num4 = 240; if (rate != 8000 && rate != 12000 && rate != 16000 && rate != 24000 && rate != 48000) { throw new ArgumentException("Sampling rate must be 8000, 12000, 16000, 24000, or 48000\n"); } int num5; if (rate != 48000) { num5 = 48000 / rate; switch (rate) { case 8000: num3 = 13; break; case 12000: num3 = 15; break; case 16000: num3 = 17; break; case 24000: num3 = 19; break; } num4 = 240 / num5; } else { num5 = 1; } if (num != num2 * num5) { throw new ArgumentException("Sample counts do not match"); } if (num < 480) { throw new ArgumentException("Insufficient sample data"); } int num6 = (num - 480 + 120) / 120; Pointer<float> pointer = Concentus.Common.CPlusPlus.Pointer.Malloc<float>(num6 * 21 * nchannels); Pointer<float> pointer2 = Concentus.Common.CPlusPlus.Pointer.Malloc<float>(num6 * 240 * nchannels); Pointer<float> pointer3 = Concentus.Common.CPlusPlus.Pointer.Malloc<float>(num6 * num4 * nchannels); band_energy(pointer, pointer2, BANDS.GetPointer(), 21, x.GetPointer(), nchannels, num6, 480, 120, 1); band_energy(null, pointer3, BANDS.GetPointer(), num3, y.GetPointer(), nchannels, num6, 480 / num5, 120 / num5, num5); for (int i = 0; i < num6; i++) { int j; for (j = 1; j < 21; j++) { for (int k = 0; k < nchannels; k++) { pointer[(i * 21 + j) * nchannels + k] += 0.1f * pointer[(i * 21 + j - 1) * nchannels + k]; } } j = 20; while (j-- > 0) { for (int k = 0; k < nchannels; k++) { pointer[(i * 21 + j) * nchannels + k] += 0.03f * pointer[(i * 21 + j + 1) * nchannels + k]; } } if (i > 0) { for (j = 0; j < 21; j++) { for (int k = 0; k < nchannels; k++) { pointer[(i * 21 + j) * nchannels + k] += 0.5f * pointer[((i - 1) * 21 + j) * nchannels + k]; } } } if (nchannels == 2) { for (j = 0; j < 21; j++) { float num7 = pointer[(i * 21 + j) * nchannels]; float num8 = pointer[(i * 21 + j) * nchannels + 1]; pointer[(i * 21 + j) * nchannels] += 0.01f * num8; pointer[(i * 21 + j) * nchannels + 1] += 0.01f * num7; } } for (j = 0; j < num3; j++) { for (int l = BANDS[j]; l < BANDS[j + 1]; l++) { for (int k = 0; k < nchannels; k++) { pointer2[(i * 240 + l) * nchannels + k] += 0.1f * pointer[(i * 21 + j) * nchannels + k]; pointer3[(i * num4 + l) * nchannels + k] += 0.1f * pointer[(i * 21 + j) * nchannels + k]; } } } } for (int j = 0; j < num3; j++) { for (int l = BANDS[j]; l < BANDS[j + 1]; l++) { for (int k = 0; k < nchannels; k++) { float num9 = pointer2[l * nchannels + k]; float num10 = pointer3[l * nchannels + k]; for (int i = 1; i < num6; i++) { float num11 = pointer2[(i * 240 + l) * nchannels + k]; float num12 = pointer3[(i * num4 + l) * nchannels + k]; pointer2[(i * 240 + l) * nchannels + k] += num9; pointer3[(i * num4 + l) * nchannels + k] += num10; num9 = num11; num10 = num12; } } } } int num13 = rate switch { 48000 => BANDS[21], 12000 => BANDS[num3], _ => BANDS[num3] - 3, }; double num14 = 0.0; for (int i = 0; i < num6; i++) { double num15 = 0.0; for (int j = 0; j < num3; j++) { double num16 = 0.0; for (int l = BANDS[j]; l < BANDS[j + 1] && l < num13; l++) { for (int k = 0; k < nchannels; k++) { float num17 = pointer3[(i * num4 + l) * nchannels + k] / pointer2[(i * 240 + l) * nchannels + k]; float num18 = num17 - (float)Math.Log(num17) - 1f; if (l >= 79 && l <= 81) { num18 *= 0.1f; } if (l == 80) { num18 *= 0.1f; } num16 += (double)num18; } } num16 /= (double)((BANDS[j + 1] - BANDS[j]) * nchannels); num15 += num16 * num16; } num15 /= 21.0; num15 *= num15; num14 += num15 * num15; } num14 = Math.Pow(num14 / (double)num6, 0.0625); float result = (float)(100.0 * (1.0 - 0.5 * Math.Log(1.0 + num14) / Math.Log(1.13))); _ = 0f; return result; } } internal static class OpusConstants { internal const int OPUS_AUTO = -1000; internal const int OPUS_BITRATE_MAX = -1; internal const int NB_FRAMES = 8; internal const int NB_TBANDS = 18; internal const int NB_TOT_BANDS = 21; internal const int NB_TONAL_SKIP_BANDS = 9; internal const int ANALYSIS_BUF_SIZE = 720; internal const int DETECT_SIZE = 200; internal const int MAX_ENCODER_BUFFER = 480; } public class OpusException : Exception { public int OpusErrorCode { get; private set; } internal OpusException() : base("Unknown error") { OpusErrorCode = -100; } internal OpusException(string message) : base(message) { OpusErrorCode = -100; } internal OpusException(int opusError) : base(CodecHelpers.opus_strerror(opusError)) { OpusErrorCode = opusError; } internal OpusException(string message, int opusError) : base(message) { OpusErrorCode = opusError; } } internal static class OpusMultistream { internal static int validate_layout(ChannelLayout layout) { int num = layout.nb_streams + layout.nb_coupled_streams; if (num > 255) { return 0; } for (int i = 0; i < layout.nb_channels; i++) { if (layout.mapping[i] >= num && layout.mapping[i] != byte.MaxValue) { return 0; } } return 1; } internal static int get_left_channel(ChannelLayout layout, int stream_id, int prev) { for (int i = ((prev >= 0) ? (prev + 1) : 0); i < layout.nb_channels; i++) { if (layout.mapping[i] == stream_id * 2) { return i; } } return -1; } internal static int get_right_channel(ChannelLayout layout, int stream_id, int prev) { for (int i = ((prev >= 0) ? (prev + 1) : 0); i < layout.nb_channels; i++) { if (layout.mapping[i] == stream_id * 2 + 1) { return i; } } return -1; } internal static int get_mono_channel(ChannelLayout layout, int stream_id, int prev) { for (int i = ((prev >= 0) ? (prev + 1) : 0); i < layout.nb_channels; i++) { if (layout.mapping[i] == stream_id + layout.nb_coupled_streams) { return i; } } return -1; } } internal static class Tables { internal static readonly float[] dct_table = new float[128] { 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.351851f, 0.33833f, 0.311806f, 0.2733f, 0.224292f, 0.166664f, 0.102631f, 0.034654f, -0.034654f, -0.102631f, -0.166664f, -0.224292f, -0.2733f, -0.311806f, -0.33833f, -0.351851f, 0.34676f, 0.293969f, 0.196424f, 0.068975f, -0.068975f, -0.196424f, -0.293969f, -0.34676f, -0.34676f, -0.293969f, -0.196424f, -0.068975f, 0.068975f, 0.196424f, 0.293969f, 0.34676f, 0.33833f, 0.224292f, 0.034654f, -0.166664f, -0.311806f, -0.351851f, -0.2733f, -0.102631f, 0.102631f, 0.2733f, 0.351851f, 0.311806f, 0.166664f, -0.034654f, -0.224292f, -0.33833f, 0.326641f, 0.135299f, -0.135299f, -0.326641f, -0.326641f, -0.135299f, 0.135299f, 0.326641f, 0.326641f, 0.135299f, -0.135299f, -0.326641f, -0.326641f, -0.135299f, 0.135299f, 0.326641f, 0.311806f, 0.034654f, -0.2733f, -0.33833f, -0.102631f, 0.224292f, 0.351851f, 0.166664f, -0.166664f, -0.351851f, -0.224292f, 0.102631f, 0.33833f, 0.2733f, -0.034654f, -0.311806f, 0.293969f, -0.068975f, -0.34676f, -0.196424f, 0.196424f, 0.34676f, 0.068975f, -0.293969f, -0.293969f, 0.068975f, 0.34676f, 0.196424f, -0.196424f, -0.34676f, -0.068975f, 0.293969f, 0.2733f, -0.166664f, -0.33833f, 0.034654f, 0.351851f, 0.102631f, -0.311806f, -0.224292f, 0.224292f, 0.311806f, -0.102631f, -0.351851f, -0.034654f, 0.33833f, 0.166664f, -0.2733f }; internal static readonly float[] analysis_window = new float[240] { 4.3E-05f, 0.000171f, 0.000385f, 0.000685f, 0.001071f, 0.001541f, 0.002098f, 0.002739f, 0.003466f, 0.004278f, 0.005174f, 0.006156f, 0.007222f, 0.008373f, 0.009607f, 0.010926f, 0.012329f, 0.013815f, 0.015385f, 0.017037f, 0.018772f, 0.02059f, 0.02249f, 0.024472f, 0.026535f, 0.028679f, 0.030904f, 0.03321f, 0.035595f, 0.03806f, 0.040604f, 0.043227f, 0.045928f, 0.048707f, 0.051564f, 0.054497f, 0.057506f, 0.060591f, 0.063752f, 0.066987f, 0.070297f, 0.07368f, 0.077136f, 0.080665f, 0.084265f, 0.087937f, 0.091679f, 0.095492f, 0.099373f, 0.103323f, 0.107342f, 0.111427f, 0.115579f, 0.119797f, 0.12408f, 0.128428f, 0.132839f, 0.137313f, 0.141849f, 0.146447f, 0.151105f, 0.155823f, 0.1606f, 0.165435f, 0.170327f, 0.175276f, 0.18028f, 0.18534f, 0.190453f, 0.195619f, 0.200838f, 0.206107f, 0.211427f, 0.216797f, 0.222215f, 0.22768f, 0.233193f, 0.238751f, 0.244353f, 0.25f, 0.255689f, 0.261421f, 0.267193f, 0.273005f, 0.278856f, 0.284744f, 0.29067f, 0.296632f, 0.302628f, 0.308658f, 0.314721f, 0.320816f, 0.326941f, 0.333097f, 0.33928f, 0.345492f, 0.351729f, 0.357992f, 0.36428f, 0.37059f, 0.376923f, 0.383277f, 0.389651f, 0.396044f, 0.402455f, 0.408882f, 0.415325f, 0.421783f, 0.428254f, 0.434737f, 0.441231f, 0.447736f, 0.454249f, 0.46077f, 0.467298f, 0.473832f, 0.48037f, 0.486912f, 0.493455f, 0.5f, 0.506545f, 0.513088f, 0.51963f, 0.526168f, 0.532702f, 0.53923f, 0.545751f, 0.552264f, 0.558769f, 0.565263f, 0.571746f, 0.578217f, 0.584675f, 0.591118f, 0.597545f, 0.603956f, 0.610349f, 0.616723f, 0.623077f, 0.62941f, 0.63572f, 0.642008f, 0.648271f, 0.654508f, 0.66072f, 0.666903f, 0.673059f, 0.679184f, 0.685279f, 0.691342f, 0.697372f, 0.703368f, 0.70933f, 0.715256f, 0.721144f, 0.726995f, 0.732807f, 0.738579f, 0.744311f, 0.75f, 0.755647f, 0.761249f, 0.766807f, 0.77232f, 0.777785f, 0.783203f, 0.788573f, 0.793893f, 0.799162f, 0.804381f, 0.809547f, 0.81466f, 0.81972f, 0.824724f, 0.829673f, 0.834565f, 0.8394f, 0.844177f, 0.848895f, 0.853553f, 0.858151f, 0.862687f, 0.867161f, 0.871572f, 0.87592f, 0.880203f, 0.884421f, 0.888573f, 0.892658f, 0.896677f, 0.900627f, 0.904508f, 0.908321f, 0.912063f, 0.915735f, 0.919335f, 0.922864f, 0.92632f, 0.929703f, 0.933013f, 0.936248f, 0.939409f, 0.942494f, 0.945503f, 0.948436f, 0.951293f, 0.954072f, 0.956773f, 0.959396f, 0.96194f, 0.964405f, 0.96679f, 0.969096f, 0.971321f, 0.973465f, 0.975528f, 0.97751f, 0.97941f, 0.981228f, 0.982963f, 0.984615f, 0.986185f, 0.987671f, 0.989074f, 0.990393f, 0.991627f, 0.992778f, 0.993844f, 0.994826f, 0.995722f, 0.996534f, 0.997261f, 0.997902f, 0.998459f, 0.998929f, 0.999315f, 0.999615f, 0.999829f, 0.999957f, 1f }; internal static readonly int[] tbands = new int[19] { 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120 }; internal static readonly int[] extra_bands = new int[22] { 1, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120, 160, 200 }; internal static readonly float[] weights = new float[422] { -0.0941125f, -0.302976f, -0.603555f, -0.19393f, -0.185983f, -0.601617f, -0.0465317f, -0.114563f, -0.103599f, -0.618938f, -0.317859f, -0.169949f, -0.0702885f, 0.148065f, 0.409524f, 0.548432f, 0.367649f, -0.494393f, 0.764306f, -1.83957f, 0.170849f, 12.786f, -1.08848f, -1.27284f, -16.2606f, 24.1773f, -5.57454f, -0.17276f, -0.163388f, -0.224421f, -0.0948944f, -0.0728695f, -0.26557f, -0.100283f, -0.0515459f, -0.146142f, -0.120674f, -0.180655f, 0.12857f, 0.442138f, -0.493735f, 0.167767f, 0.206699f, -0.197567f, 0.417999f, 1.50364f, -0.773341f, -10.0401f, 0.401872f, 2.97966f, 15.2165f, -1.88905f, -1.19254f, 0.0285397f, -0.00405139f, 0.0707565f, 0.00825699f, -0.0927269f, -0.010393f, -0.00428882f, -0.00489743f, -0.0709731f, -0.00255992f, 0.0395619f, 0.226424f, 0.0325231f, 0.162175f, -0.100118f, 0.485789f, 0.12697f, 0.285937f, 0.0155637f, 0.10546f, 3.05558f, 1.15059f, -1.00904f, -1.83088f, 3.31766f, -3.42516f, -0.119135f, -0.0405654f, 0.00690068f, 0.0179877f, -0.0382487f, 0.00597941f, -0.0183611f, 0.00190395f, -0.144322f, -0.0435671f, 0.000990594f, 0.221087f, 0.142405f, 0.484066f, 0.404395f, 0.511955f, -0.237255f, 0.241742f, 0.35045f, -0.699428f, 10.3993f, 2.6507f, -2.43459f, -4.18838f, 1.05928f, 1.71067f, 0.00667811f, -0.0721335f, -0.0397346f, 0.0362704f, -0.11496f, -0.0235776f, 0.0082161f, -0.0141741f, -0.0329699f, -0.0354253f, 0.00277404f, -0.290654f, -1.14767f, -0.319157f, -0.686544f, 0.36897f, 0.478899f, 0.182579f, -0.411069f, 0.881104f, -4.60683f, 1.4697f, 325f / (356f * MathF.E), -1.81905f, -30.1699f, 5.55225f, 0.0019508f, -0.123576f, -0.0727332f, -0.0641597f, -0.0534458f, -0.108166f, -0.0937368f, -0.0697883f, -0.0275475f, -0.192309f, -0.110074f, 0.285375f, -0.405597f, 0.0926724f, -0.287881f, -0.851193f, -0.099493f, -0.233764f, -1.2852f, 1.13611f, 3.12168f, -0.0699f, -1.86216f, 2.65292f, -7.31036f, 2.44776f, -0.00111802f, -0.0632786f, -0.0376296f, -0.149851f, 0.142963f, 0.184368f, 0.123433f, 0.0756158f, 0.117312f, 0.0933395f, 0.0692163f, 0.0842592f, 0.0704683f, 0.0589963f, 0.0942205f, -0.448862f, 0.0262677f, 0.270352f, -0.262317f, 0.172586f, 2.00227f, -0.159216f, 0.038422f, 10.2073f, 4.15536f, -2.3407f, -0.0550265f, 0.00964792f, -0.141336f, 0.0274501f, 0.0343921f, -0.0487428f, 0.0950172f, -0.00775017f, -0.0372492f, -0.00548121f, -0.0663695f, 0.0960506f, -0.200008f, -0.0412827f, 0.58728f, 0.0515787f, 0.337254f, 0.855024f, 0.668371f, -0.114904f, -3.62962f, -0.467477f, -0.215472f, 2.61537f, 0.406117f, -1.36373f, 0.0425394f, 0.12208f, 0.0934502f, 0.123055f, 0.0340935f, -0.142466f, 0.035037f, -0.0490666f, 0.0733208f, 0.0576672f, 0.123984f, -0.0517194f, -0.253018f, 0.590565f, 0.145849f, 0.315185f, 0.221534f, -0.149081f, 0.216161f, -0.349575f, 24.5664f, -0.994196f, 0.614289f, -18.7905f, -2.83277f, -0.716801f, -0.347201f, 0.479515f, -0.246027f, 0.0758683f, 0.137293f, -0.17781f, 0.118751f, -0.00108329f, -0.237334f, 0.355732f, -0.12991f, -0.0547627f, -0.318576f, -0.325524f, 0.180494f, -0.0625604f, 0.141219f, 0.344064f, 0.37658f, -0.591772f, 5.8427f, -0.38075f, 0.221894f, -1.41934f, -1879430f, 1.34114f, 0.0283355f, -0.0447856f, -0.0211466f, -0.0256927f, 0.0139618f, 0.0207934f, -0.0107666f, 0.0110969f, 0.0586069f, -0.0253545f, -0.0328433f, 0.11872f, -0.216943f, 0.145748f, 0.119808f, -0.0915211f, -0.120647f, -0.0787719f, -0.143644f, -0.595116f, -1.152f, -1.25335f, -1.17092f, 4.34023f, -975268f, -1.37033f, -0.0401123f, 0.210602f, -0.136656f, 0.135962f, -0.0523293f, 0.0444604f, 0.0143928f, 0.00412666f, -0.0193003f, 0.218452f, -0.110204f, -2.02563f, 0.918238f, -2.45362f, 1.19542f, -0.061362f, -1.92243f, 0.308111f, 0.49764f, 0.912356f, 0.209272f, -2.34525f, 2.19326f, -6.47121f, 1.69771f, -0.725123f, 0.0118929f, 0.0377944f, 0.0554003f, 0.0226452f, -0.0704421f, -0.0300309f, 0.0122978f, -0.0041782f, -0.0686612f, 0.0313115f, 0.039111f, 0.364111f, -0.0945548f, 0.0229876f, -0.17414f, 0.329795f, 0.114714f, 0.30022f, 0.106997f, 0.132355f, 5.79932f, 0.908058f, -0.905324f, -3.3561f, 0.190647f, 0.184211f, -0.673648f, 0.231807f, -0.0586222f, 0.230752f, -0.438277f, 0.245857f, -0.17215f, 0.0876383f, -0.720512f, 0.162515f, 0.0170571f, 0.101781f, 0.388477f, 1.32931f, 1.08548f, -0.936301f, -2.36958f, -6.71988f, -3.44376f, 2.13818f, 14.2318f, 4.91459f, -3.09052f, -9.69191f, -0.768234f, 1.79604f, 0.0549653f, 0.163399f, 0.0797025f, 0.0343933f, -0.0555876f, -0.00505673f, 0.0187258f, 0.0326628f, 0.0231486f, 0.15573f, 0.0476223f, -0.254824f, 1.60155f, -0.801221f, 2.55496f, 0.737629f, -1.36249f, -0.695463f, -2.44301f, -1.73188f, 3.95279f, 1.89068f, 0.486087f, -11.3343f, 3941600f, -0.381439f, 0.12115f, -0.906927f, 2.93878f, 1.6388f, 0.882811f, 0.874344f, 1.21726f, -0.874545f, 0.321706f, 0.785055f, 0.946558f, -0.575066f, -3.46553f, 0.884905f, 0.0924047f, -9.90712f, 0.391338f, 0.160103f, -2.04954f, 4.1455f, 0.0684029f, -0.144761f, -0.285282f, 0.379244f, -1.1584f, -0.0277241f, -9.85f, -4.82386f, 3.71333f, 3.87308f, 3.52558f }; internal static readonly int[] topo = new int[3] { 25, 15, 2 }; internal static readonly MLP net = new MLP { layers = 3, topo = topo, weights = weights }; internal static readonly float[] tansig_table = new float[201] { 0f, 0.039979f, 0.07983f, 0.119427f, 0.158649f, 0.197375f, 0.235496f, 0.272905f, 0.309507f, 0.345214f, 0.379949f, 0.413644f, 0.446244f, 0.4777f, 0.507977f, 0.53705f, 0.5649f, 0.591519f, 0.616909f, 0.641077f, 0.664037f, 0.685809f, 0.706419f, 0.725897f, 0.744277f, 0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.82104f, 0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f, 0.885352f, 0.893698f, 0.901468f, 0.908698f, 0.91542f, 0.921669f, 0.927473f, 0.932862f, 0.937863f, 0.942503f, 0.946806f, 0.950795f, 0.954492f, 0.957917f, 0.96109f, 0.964028f, 0.966747f, 0.969265f, 0.971594f, 0.973749f, 0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f, 0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f, 0.989027f, 0.989867f, 0.990642f, 0.991359f, 0.99202f, 0.992631f, 0.993196f, 0.993718f, 0.994199f, 0.994644f, 0.995055f, 0.995434f, 0.995784f, 0.996108f, 0.996407f, 0.996682f, 0.996937f, 0.997172f, 0.997389f, 0.99759f, 0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f, 0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f, 0.999f, 0.999076f, 0.999147f, 0.999213f, 0.999273f, 0.999329f, 0.999381f, 0.999428f, 0.999472f, 0.999513f, 0.99955f, 0.999585f, 0.999617f, 0.999646f, 0.999673f, 0.999699f, 0.999722f, 0.999743f, 0.999763f, 0.999781f, 0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f, 0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f, 0.999909f, 0.999916f, 0.999923f, 0.999929f, 0.999934f, 0.999939f, 0.999944f, 0.999948f, 0.999952f, 0.999956f, 0.999959f, 0.999962f, 0.999965f, 0.999968f, 0.99997f, 0.999973f, 0.999975f, 0.999977f, 0.999978f, 0.99998f, 0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f, 0.999988f, 0.999989f, 0.99999f, 0.99999f, 0.999991f, 0.999992f, 0.999992f, 0.999993f, 0.999994f, 0.999994f, 0.999994f, 0.999995f, 0.999995f, 0.999996f, 0.999996f, 0.999996f, 0.999997f, 0.999997f, 0.999997f, 0.999997f, 0.999997f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f }; internal static readonly int[] mono_voice_bandwidth_thresholds = new int[8] { 11000, 1000, 14000, 1000, 17000, 1000, 21000, 2000 }; internal static readonly int[] mono_music_bandwidth_thresholds = new int[8] { 12000, 1000, 15000, 1000, 18000, 2000, 22000, 2000 }; internal static readonly int[] stereo_voice_bandwidth_thresholds = new int[8] { 11000, 1000, 14000, 1000, 21000, 2000, 28000, 2000 }; internal static readonly int[] stereo_music_bandwidth_thresholds = new int[8] { 12000, 1000, 18000, 2000, 21000, 2000, 30000, 2000 }; internal const int stereo_voice_threshold = 30000; internal const int stereo_music_threshold = 30000; internal static readonly int[][] mode_thresholds = new int[2][] { new int[2] { 64000, 16000 }, new int[2] { 36000, 16000 } }; } public static class ResamplerFactory { public static IResampler CreateResampler(int numChannels, int inRate, int outRate, int quality, TextWriter logger = null) { return CreateResampler(numChannels, inRate, outRate, inRate, outRate, quality, logger); } public static IResampler CreateResampler(int numChannels, int ratioNum, int ratioDen, int inRate, int outRate, int quality, TextWriter logger = null) { if (numChannels <= 0) { throw new ArgumentOutOfRangeException("numChannels"); } if (ratioNum <= 0) { throw new ArgumentOutOfRangeException("ratioNum"); } if (ratioDen <= 0) { throw new ArgumentOutOfRangeException("ratioDen"); } if (inRate <= 0) { throw new ArgumentOutOfRangeException("inRate"); } if (outRate <= 0) { throw new ArgumentOutOfRangeException("outRate"); } if (quality < 0 || quality > 10) { throw new ArgumentOutOfRangeException("quality", "Quality must be between 0 and 10"); } return new SpeexResampler(numChannels, ratioNum, ratioDen, inRate, outRate, quality); } } } namespace Concentus.Silk { internal static class ApplySineWindow { private static readonly short[] freq_table_Q16 = new short[27] { 12111, 9804, 8235, 7100, 6239, 5565, 5022, 4575, 4202, 3885, 3612, 3375, 3167, 2984, 2820, 2674, 2542, 2422, 2313, 2214, 2123, 2038, 1961, 1889, 1822, 1760, 1702 }; internal static void silk_apply_sine_window(short[] px_win, int px_win_ptr, short[] px, int px_ptr, int win_type, int length) { int num = (length >> 2) - 4; int num2 = freq_table_Q16[num]; int num3 = Inlines.silk_SMULWB(num2, -num2); int num4; int num5; if (win_type == 1) { num4 = 0; num5 = num2 + Inlines.silk_RSHIFT(length, 3); } else { num4 = 65536; num5 = 65536 + Inlines.silk_RSHIFT(num3, 1) + Inlines.silk_RSHIFT(length, 4); } for (num = 0; num < length; num += 4) { int num6 = px_win_ptr + num; int num7 = px_ptr + num; px_win[num6] = (short)Inlines.silk_SMULWB(Inlines.silk_RSHIFT(num4 + num5, 1), px[num7]); px_win[num6 + 1] = (short)Inlines.silk_SMULWB(num5, px[num7 + 1]); num4 = Inlines.silk_SMULWB(num5, num3) + Inlines.silk_LSHIFT(num5, 1) - num4 + 1; num4 = Inlines.silk_min(num4, 65536); px_win[num6 + 2] = (short)Inlines.silk_SMULWB(Inlines.silk_RSHIFT(num4 + num5, 1), px[num7 + 2]); px_win[num6 + 3] = (short)Inlines.silk_SMULWB(num4, px[num7 + 3]); num5 = Inlines.silk_SMULWB(num4, num3) + Inlines.silk_LSHIFT(num4, 1) - num5; num5 = Inlines.silk_min(num5, 65536); } } } internal static class BurgModified { private const int MAX_FRAME_SIZE = 384; private const int QA = 25; private const int N_BITS_HEAD_ROOM = 2; private const int MIN_RSHIFTS = -16; private const int MAX_RSHIFTS = 7; internal static void silk_burg_modified(BoxedValueInt res_nrg, BoxedValueInt res_nrg_Q, int[] A_Q16, short[] x, int x_ptr, int minInvGain_Q30, int subfr_length, int nb_subfr, int D) { int[] array = new int[16]; int[] array2 = new int[16]; int[] array3 = new int[16]; int[] array4 = new int[17]; int[] array5 = new int[17]; int[] array6 = new int[16]; long num = Inlines.silk_inner_prod16_aligned_64(x, x_ptr, x, x_ptr, subfr_length * nb_subfr); int num2 = Inlines.silk_CLZ64(num); int num3 = 35 - num2; if (num3 > 7) { num3 = 7; } if (num3 < -16) { num3 = -16; } int num4 = (int)((num3 <= 0) ? Inlines.silk_LSHIFT32((int)num, -num3) : Inlines.silk_RSHIFT64(num, num3)); array5[0] = (array4[0] = num4 + Inlines.silk_SMMUL(42950, num4) + 1); Arrays.MemSetInt(array, 0, 16); if (num3 > 0) { for (int i = 0; i < nb_subfr; i++) { int num5 = x_ptr + i * subfr_length; for (int j = 1; j < D + 1; j++) { array[j - 1] += (int)Inlines.silk_RSHIFT64(Inlines.silk_inner_prod16_aligned_64(x, num5, x, num5 + j, subfr_length - j), num3); } } } else { for (int i = 0; i < nb_subfr; i++) { int num5 = x_ptr + i * subfr_length; CeltPitchXCorr.pitch_xcorr(x, num5, x, num5 + 1, array6, subfr_length - D, D); for (int j = 1; j < D + 1; j++) { int k = j + subfr_length - D; int num6 = 0; for (; k < subfr_length; k++) { num6 = Inlines.MAC16_16(num6, x[num5 + k], x[num5 + k - j]); } array6[j - 1] += num6; } for (int j = 1; j < D + 1; j++) { array[j - 1] += Inlines.silk_LSHIFT32(array6[j - 1], -num3); } } } Arrays.MemCopy(array, 0, array2, 0, 16); array5[0] = (array4[0] = num4 + Inlines.silk_SMMUL(42950, num4) + 1); int num7 = 1073741824; int num8 = 0; for (int j = 0; j < D; j++) { int num9; int num10; if (num3 > -2) { for (int i = 0; i < nb_subfr; i++) { int num5 = x_ptr + i * subfr_length; int b = -Inlines.silk_LSHIFT32(x[num5 + j], 16 - num3); int b2 = -Inlines.silk_LSHIFT32(x[num5 + subfr_length - j - 1], 16 - num3); num9 = Inlines.silk_LSHIFT32(x[num5 + j], 9); num10 = Inlines.silk_LSHIFT32(x[num5 + subfr_length - j - 1], 9); for (int l = 0; l < j; l++) { array[l] = Inlines.silk_SMLAWB(array[l], b, x[num5 + j - l - 1]); array2[l] = Inlines.silk_SMLAWB(array2[l], b2, x[num5 + subfr_length - j + l]); int b3 = array3[l]; num9 = Inlines.silk_SMLAWB(num9, b3, x[num5 + j - l - 1]); num10 = Inlines.silk_SMLAWB(num10, b3, x[num5 + subfr_length - j + l]); } num9 = Inlines.silk_LSHIFT32(-num9, 7 - num3); num10 = Inlines.silk_LSHIFT32(-num10, 7 - num3); for (int l = 0; l <= j; l++) { array4[l] = Inlines.silk_SMLAWB(array4[l], num9, x[num5 + j - l]); array5[l] = Inlines.silk_SMLAWB(array5[l], num10, x[num5 + subfr_length - j + l - 1]); } } } else { for (int i = 0; i < nb_subfr; i++) { int num5 = x_ptr + i * subfr_length; int b = -Inlines.silk_LSHIFT32(x[num5 + j], -num3); int b2 = -Inlines.silk_LSHIFT32(x[num5 + subfr_length - j - 1], -num3); num9 = Inlines.silk_LSHIFT32(x[num5 + j], 17); num10 = Inlines.silk_LSHIFT32(x[num5 + subfr_length - j - 1], 17); for (int l = 0; l < j; l++) { array[l] = Inlines.silk_MLA(array[l], b, x[num5 + j - l - 1]); array2[l] = Inlines.silk_MLA(array2[l], b2, x[num5 + subfr_length - j + l]); int c = Inlines.silk_RSHIFT_ROUND(array3[l], 8); num9 = Inlines.silk_MLA(num9, x[num5 + j - l - 1], c); num10 = Inlines.silk_MLA(num10, x[num5 + subfr_length - j + l], c); } num9 = -num9; num10 = -num10; for (int l = 0; l <= j; l++) { array4[l] = Inlines.silk_SMLAWW(array4[l], num9, Inlines.silk_LSHIFT32(x[num5 + j - l], -num3 - 1)); array5[l] = Inlines.silk_SMLAWW(array5[l], num10, Inlines.silk_LSHIFT32(x[num5 + subfr_length - j + l - 1], -num3 - 1)); } } } num9 = array[j]; num10 = array2[j]; int a = 0; int num11 = Inlines.silk_ADD32(array5[0], array4[0]); for (int l = 0; l < j; l++) { int b3 = array3[l]; num2 = Inlines.silk_CLZ32(Inlines.silk_abs(b3)) - 1; num2 = Inlines.silk_min(7, num2); int c = Inlines.silk_LSHIFT32(b3, num2); num9 = Inlines.silk_ADD_LSHIFT32(num9, Inlines.silk_SMMUL(array2[j - l - 1], c), 7 - num2); num10 = Inlines.silk_ADD_LSHIFT32(num10, Inlines.silk_SMMUL(array[j - l - 1], c), 7 - num2); a = Inlines.silk_ADD_LSHIFT32(a, Inlines.silk_SMMUL(array5[j - l], c), 7 - num2); num11 = Inlines.silk_ADD_LSHIFT32(num11, Inlines.silk_SMMUL(Inlines.silk_ADD32(array5[l + 1], array4[l + 1]), c), 7 - num2); } array4[j + 1] = num9; array5[j + 1] = num10; a = Inlines.silk_ADD32(a, num10); a = Inlines.silk_LSHIFT32(-a, 1); int num12 = ((Inlines.silk_abs(a) >= num11) ? ((a > 0) ? int.MaxValue : int.MinValue) : Inlines.silk_DIV32_varQ(a, num11, 31)); num9 = 1073741824 - Inlines.silk_SMMUL(num12, num12); num9 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(num7, num9), 2); if (num9 <= minInvGain_Q30) { num10 = 1073741824 - Inlines.silk_DIV32_varQ(minInvGain_Q30, num7, 30); num12 = Inlines.silk_SQRT_APPROX(num10); num12 = Inlines.silk_RSHIFT32(num12 + Inlines.silk_DIV32(num10, num12), 1); num12 = Inlines.silk_LSHIFT32(num12, 16); if (a < 0) { num12 = -num12; } num7 = minInvGain_Q30; num8 = 1; } else { num7 = num9; } for (int l = 0; l < j + 1 >> 1; l++) { num9 = array3[l]; num10 = array3[j - l - 1]; array3[l] = Inlines.silk_ADD_LSHIFT32(num9, Inlines.silk_SMMUL(num10, num12), 1); array3[j - l - 1] = Inlines.silk_ADD_LSHIFT32(num10, Inlines.silk_SMMUL(num9, num12), 1); } array3[j] = Inlines.silk_RSHIFT32(num12, 6); if (num8 != 0) { for (int l = j + 1; l < D; l++) { array3[l] = 0; } break; } for (int l = 0; l <= j + 1; l++) { num9 = array4[l]; num10 = array5[j - l + 1]; array4[l] = Inlines.silk_ADD_LSHIFT32(num9, Inlines.silk_SMMUL(num10, num12), 1); array5[j - l + 1] = Inlines.silk_ADD_LSHIFT32(num10, Inlines.silk_SMMUL(num9, num12), 1); } } if (num8 != 0) { for (int l = 0; l < D; l++) { A_Q16[l] = -Inlines.silk_RSHIFT_ROUND(array3[l], 9); } if (num3 > 0) { for (int i = 0; i < nb_subfr; i++) { int num5 = x_ptr + i * subfr_length; num4 -= (int)Inlines.silk_RSHIFT64(Inlines.silk_inner_prod16_aligned_64(x, num5, x, num5, D), num3); } } else { for (int i = 0; i < nb_subfr; i++) { int num5 = x_ptr + i * subfr_length; num4 -= Inlines.silk_LSHIFT32(Inlines.silk_inner_prod_self(x, num5, D), -num3); } } res_nrg.Val = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(num7, num4), 2); res_nrg_Q.Val = -num3; } else { int num11 = array4[0]; int num9 = 65536; for (int l = 0; l < D; l++) { int c = Inlines.silk_RSHIFT_ROUND(array3[l], 9); num11 = Inlines.silk_SMLAWW(num11, array4[l + 1], c); num9 = Inlines.silk_SMLAWW(num9, c, c); A_Q16[l] = -c; } res_nrg.Val = Inlines.silk_SMLAWW(num11, Inlines.silk_SMMUL(42950, num4), -num9); res_nrg_Q.Val = -num3; } } } internal static class BWExpander { internal static void silk_bwexpander_32(int[] ar, int d, int chirp_Q16) { int b = chirp_Q16 - 65536; for (int i = 0; i < d - 1; i++) { ar[i] = Inlines.silk_SMULWW(chirp_Q16, ar[i]); chirp_Q16 += Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, b), 16); } ar[d - 1] = Inlines.silk_SMULWW(chirp_Q16, ar[d - 1]); } internal static void silk_bwexpander(short[] ar, int d, int chirp_Q16) { int b = chirp_Q16 - 65536; for (int i = 0; i < d - 1; i++) { ar[i] = (short)Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, ar[i]), 16); chirp_Q16 += Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, b), 16); } ar[d - 1] = (short)Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, ar[d - 1]), 16); } } internal static class CNG { internal static void silk_CNG_exc(Span<int> exc_Q10, int exc_Q10_ptr, int[] exc_buf_Q14, int Gain_Q16, int length, ref int rand_seed) { int num; for (num = 255; num > length; num = Inlines.silk_RSHIFT(num, 1)) { } int num2 = rand_seed; for (int i = exc_Q10_ptr; i < exc_Q10_ptr + length; i++) { num2 = Inlines.silk_RAND(num2); int num3 = Inlines.silk_RSHIFT(num2, 24) & num; exc_Q10[i] = (short)Inlines.silk_SAT16(Inlines.silk_SMULWW(exc_buf_Q14[num3], Gain_Q16 >> 4)); } rand_seed = num2; } internal static void silk_CNG_Reset(SilkChannelDecoder psDec) { int num = Inlines.silk_DIV32_16(32767, (short)(psDec.LPC_order + 1)); int num2 = 0; for (int i = 0; i < psDec.LPC_order; i++) { num2 += num; psDec.sCNG.CNG_smth_NLSF_Q15[i] = (short)num2; } psDec.sCNG.CNG_smth_Gain_Q16 = 0; psDec.sCNG.rand_seed = 3176576; } internal static void silk_CNG(SilkChannelDecoder psDec, SilkDecoderControl psDecCtrl, Span<short> frame, int frame_ptr, int length) { short[] array = new short[psDec.LPC_order]; CNGState sCNG = psDec.sCNG; if (psDec.fs_kHz != sCNG.fs_kHz) { silk_CNG_Reset(psDec); sCNG.fs_kHz = psDec.fs_kHz; } if (psDec.lossCnt == 0 && psDec.prevSignalType == 0) { for (int i = 0; i < psDec.LPC_order; i++) { sCNG.CNG_smth_NLSF_Q15[i] += (short)Inlines.silk_SMULWB(psDec.prevNLSF_Q15[i] - sCNG.CNG_smth_NLSF_Q15[i], 16348); } int num = 0; for (int i = 0; i < psDec.nb_subfr; i++) { if (psDecCtrl.Gains_Q16[i] > num) { num = psDecCtrl.Gains_Q16[i]; } } Arrays.MemMoveInt(sCNG.CNG_exc_buf_Q14, 0, psDec.subfr_length, (psDec.nb_subfr - 1) * psDec.subfr_length); for (int i = 0; i < psDec.nb_subfr; i++) { sCNG.CNG_smth_Gain_Q16 += Inlines.silk_SMULWB(psDecCtrl.Gains_Q16[i] - sCNG.CNG_smth_Gain_Q16, 4634); } } if (psDec.lossCnt != 0) { int[] array2 = new int[length + 16]; int num2 = Inlines.silk_SMULWW(psDec.sPLC.randScale_Q14, psDec.sPLC.prevGain_Q16[1]); if (num2 >= 2097152 || sCNG.CNG_smth_Gain_Q16 > 8388608) { num2 = Inlines.silk_SMULTT(num2, num2); num2 = Inlines.silk_SUB_LSHIFT32(Inlines.silk_SMULTT(sCNG.CNG_smth_Gain_Q16, sCNG.CNG_smth_Gain_Q16), num2, 5); num2 = Inlines.silk_LSHIFT32(Inlines.silk_SQRT_APPROX(num2), 16); } else { num2 = Inlines.silk_SMULWW(num2, num2); num2 = Inlines.silk_SUB_LSHIFT32(Inlines.silk_SMULWW(sCNG.CNG_smth_Gain_Q16, sCNG.CNG_smth_Gain_Q16), num2, 5); num2 = Inlines.silk_LSHIFT32(Inlines.silk_SQRT_APPROX(num2), 8); } silk_CNG_exc(array2, 16, sCNG.CNG_exc_buf_Q14, num2, length, ref sCNG.rand_seed); NLSF.silk_NLSF2A(array, sCNG.CNG_smth_NLSF_Q15, psDec.LPC_order); Arrays.MemCopy(sCNG.CNG_synth_state, 0, array2, 0, 16); for (int i = 0; i < length; i++) { int num3 = 16 + i; int a = Inlines.silk_RSHIFT(psDec.LPC_order, 1); a = Inlines.silk_SMLAWB(a, array2[num3 - 1], array[0]); a = Inlines.silk_SMLAWB(a, array2[num3 - 2], array[1]); a = Inlines.silk_SMLAWB(a, array2[num3 - 3], array[2]); a = Inlines.silk_SMLAWB(a, array2[num3 - 4], array[3]); a = Inlines.silk_SMLAWB(a, array2[num3 - 5], array[4]); a = Inlines.silk_SMLAWB(a, array2[num3 - 6], array[5]); a = Inlines.silk_SMLAWB(a, array2[num3 - 7], array[6]); a = Inlines.silk_SMLAWB(a, array2[num3 - 8], array[7]); a = Inlines.silk_SMLAWB(a, array2[num3 - 9], array[8]); a = Inlines.silk_SMLAWB(a, array2[num3 - 10], array[9]); if (psDec.LPC_order == 16) { a = Inlines.silk_SMLAWB(a, array2[num3 - 11], array[10]); a = Inlines.silk_SMLAWB(a, array2[num3 - 12], array[11]); a = Inlines.silk_SMLAWB(a, array2[num3 - 13], array[12]); a = Inlines.silk_SMLAWB(a, array2[num3 - 14], array[13]); a = Inlines.silk_SMLAWB(a, array2[num3 - 15], array[14]); a = Inlines.silk_SMLAWB(a, array2[num3 - 16], array[15]); } array2[num3] = Inlines.silk_ADD_LSHIFT(array2[num3], a, 4); frame[frame_ptr + i] = Inlines.silk_ADD_SAT16(frame[frame_ptr + i], (short)Inlines.silk_RSHIFT_ROUND(array2[num3], 10)); } Arrays.MemCopy(array2, length, sCNG.CNG_synth_state, 0, 16); } else { Arrays.MemSetInt(sCNG.CNG_synth_state, 0, psDec.LPC_order); } } } internal static class CodeSigns { private static int silk_enc_map(int a) { return Inlines.silk_RSHIFT(a, 15) + 1; } private static int silk_dec_map(int a) { return Inlines.silk_LSHIFT(a, 1) - 1; } internal static void silk_encode_signs(EntropyCoder psRangeEnc, Span<byte> encodedData, Span<sbyte> pulses, int length, int signalType, int quantOffsetType, int[] sum_pulses) { byte[] array = new byte[2]; byte[] silk_sign_iCDF = Tables.silk_sign_iCDF; array[1] = 0; int num = 0; int num2 = Inlines.silk_SMULBB(7, Inlines.silk_ADD_LSHIFT(quantOffsetType, signalType, 1)); int num3 = num2; length = Inlines.silk_RSHIFT(length + 8, 4); for (num2 = 0; num2 < length; num2++) { int num4 = sum_pulses[num2]; if (num4 > 0) { array[0] = silk_sign_iCDF[num3 + Inlines.silk_min(num4 & 0x1F, 6)]; for (int i = num; i < num + 16; i++) { if (pulses[i] != 0) { psRangeEnc.enc_icdf(encodedData, silk_enc_map(pulses[i]), array, 8u); } } } num += 16; } } internal static void silk_decode_signs(EntropyCoder psRangeDec, ReadOnlySpan<byte> encodedData, short[] pulses, int length, int signalType, int quantOffsetType, int[] sum_pulses) { byte[] array = new byte[2]; byte[] silk_sign_iCDF = Tables.silk_sign_iCDF; array[1] = 0; int num = 0; int num2 = Inlines.silk_SMULBB(7, Inlines.silk_ADD_LSHIFT(quantOffsetType, signalType, 1)); int num3 = num2; length = Inlines.silk_RSHIFT(length + 8, 4); for (num2 = 0; num2 < length; num2++) { int num4 = sum_pulses[num2]; if (num4 > 0) { array[0] = silk_sign_iCDF[num3 + Inlines.silk_min(num4 & 0x1F, 6)]; for (int i = 0; i < 16; i++) { if (pulses[num + i] > 0) { pulses[num + i] *= (short)silk_dec_map(psRangeDec.dec_icdf(encodedData, array, 8u)); } } } num += 16; } } } internal static class CorrelateMatrix { internal static void silk_corrVector(short[] x, int x_ptr, short[] t, int t_ptr, int L, int order, int[] Xt, int rshifts) { int num = x_ptr + order - 1; if (rshifts > 0) { for (int i = 0; i < order; i++) { int num2 = 0; for (int j = 0; j < L; j++) { num2 += Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num + j], t[t_ptr + j]), rshifts); } Xt[i] = num2; num--; } } else { for (int i = 0; i < order; i++) { Xt[i] = Inlines.silk_inner_prod(x, num, t, t_ptr, L); num--; } } } internal static void silk_corrMatrix(short[] x, int x_ptr, int L, int order, int head_room, int[] XX, int XX_ptr, BoxedValueInt rshifts) { SumSqrShift.silk_sum_sqr_shift(out var energy, out var shift, x, x_ptr, L + order - 1); int num = Inlines.silk_max(head_room - Inlines.silk_CLZ32(energy), 0); energy = Inlines.silk_RSHIFT32(energy, num); shift += num; for (int i = x_ptr; i < x_ptr + order - 1; i++) { energy -= Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[i], x[i]), shift); } if (shift < rshifts.Val) { energy = Inlines.silk_RSHIFT32(energy, rshifts.Val - shift); shift = rshifts.Val; } Inlines.MatrixSet(XX, XX_ptr, 0, 0, order, energy); int num2 = x_ptr + order - 1; for (int j = 1; j < order; j++) { energy = Inlines.silk_SUB32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num2 + L - j], x[num2 + L - j]), shift)); energy = Inlines.silk_ADD32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num2 - j], x[num2 - j]), shift)); Inlines.MatrixSet(XX, XX_ptr, j, j, order, energy); } int num3 = x_ptr + order - 2; if (shift > 0) { for (int k = 1; k < order; k++) { energy = 0; for (int i = 0; i < L; i++) { energy += Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num2 + i], x[num3 + i]), shift); } Inlines.MatrixSet(XX, XX_ptr, k, 0, order, energy); Inlines.MatrixSet(XX, XX_ptr, 0, k, order, energy); for (int j = 1; j < order - k; j++) { energy = Inlines.silk_SUB32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num2 + L - j], x[num3 + L - j]), shift)); energy = Inlines.silk_ADD32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num2 - j], x[num3 - j]), shift)); Inlines.MatrixSet(XX, XX_ptr, k + j, j, order, energy); Inlines.MatrixSet(XX, XX_ptr, j, k + j, order, energy); } num3--; } } else { for (int k = 1; k < order; k++) { energy = Inlines.silk_inner_prod(x, num2, x, num3, L); Inlines.MatrixSet(XX, XX_ptr, k, 0, order, energy); Inlines.MatrixSet(XX, XX_ptr, 0, k, order, energy); for (int j = 1; j < order - k; j++) { energy = Inlines.silk_SUB32(energy, Inlines.silk_SMULBB(x[num2 + L - j], x[num3 + L - j])); energy = Inlines.silk_SMLABB(energy, x[num2 - j], x[num3 - j]); Inlines.MatrixSet(XX, XX_ptr, k + j, j, order, energy); Inlines.MatrixSet(XX, XX_ptr, j, k + j, order, energy); } num3--; } } rshifts.Val = shift; } } internal static class DecodeAPI { internal static int silk_InitDecoder(SilkDecoder decState) { decState.Reset(); int result = SilkError.SILK_NO_ERROR; SilkChannelDecoder[] channel_state = decState.channel_state; for (int i = 0; i < 2; i++) { result = channel_state[i].silk_init_decoder(); } decState.sStereo.Reset(); decState.prev_decode_only_middle = 0; return result; } internal static int silk_Decode(SilkDecoder psDec, DecControlState decControl, ReadOnlySpan<byte> frameData, int lostFlag, int newPacketFlag, EntropyCoder psRangeDec, Span<short> samplesOut, int samplesOut_ptr, out int nSamplesOut) { int num = 0; int num2 = SilkError.SILK_NO_ERROR; BoxedValueInt boxedValueInt = new BoxedValueInt(); int[] array = new int[2]; int[] array2 = new int[2]; SilkChannelDecoder[] channel_state = psDec.channel_state; nSamplesOut = 0; if (newPacketFlag != 0) { for (int i = 0; i < decControl.nChannelsInternal; i++) { channel_state[i].nFramesDecoded = 0; } } if (decControl.nChannelsInternal > psDec.nChannelsInternal) { num2 += channel_state[1].silk_init_decoder(); } int num3 = ((decControl.nChannelsInternal == 1 && psDec.nChannelsInternal == 2 && decControl.internalSampleRate == 1000 * channel_state[0].fs_kHz) ? 1 : 0); if (channel_state[0].nFramesDecoded == 0) { for (int i = 0; i < decControl.nChannelsInternal; i++) { if (decControl.payloadSize_ms == 0) { channel_state[i].nFramesPerPacket = 1; channel_state[i].nb_subfr = 2; } else if (decControl.payloadSize_ms == 10) { channel_state[i].nFramesPerPacket = 1; channel_state[i].nb_subfr = 2; } else if (decControl.payloadSize_ms == 20) { channel_state[i].nFramesPerPacket = 1; channel_state[i].nb_subfr = 4; } else if (decControl.payloadSize_ms == 40) { channel_state[i].nFramesPerPacket = 2; channel_state[i].nb_subfr = 4; } else { if (decControl.payloadSize_ms != 60) { return SilkError.SILK_DEC_INVALID_FRAME_SIZE; } channel_state[i].nFramesPerPacket = 3; channel_state[i].nb_subfr = 4; } int num4 = (decControl.internalSampleRate >> 10) + 1; if (num4 != 8 && num4 != 12 && num4 != 16) { return SilkError.SILK_DEC_INVALID_SAMPLING_FREQUENCY; } num2 += channel_state[i].silk_decoder_set_fs(num4, decControl.API_sampleRate); } } if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 2 && (psDec.nChannelsAPI == 1 || psDec.nChannelsInternal == 1)) { Arrays.MemSetShort(psDec.sStereo.pred_prev_Q13, 0, 2); Arrays.MemSetShort(psDec.sStereo.sSide, 0, 2); channel_state[1].resampler_state.Assign(channel_state[0].resampler_state); } psDec.nChannelsAPI = decControl.nChannelsAPI; psDec.nChannelsInternal = decControl.nChannelsInternal; if (decControl.API_sampleRate > 48000 || decControl.API_sampleRate < 8000) { return SilkError.SILK_DEC_INVALID_SAMPLING_FREQUENCY; } if (lostFlag != 1 && channel_state[0].nFramesDecoded == 0) { for (int i = 0; i < decControl.nChannelsInternal; i++) { for (int j = 0; j < channel_state[i].nFramesPerPacket; j++) { channel_state[i].VAD_flags[j] = psRangeDec.dec_bit_logp(frameData, 1u); } channel_state[i].LBRR_flag = psRangeDec.dec_bit_logp(frameData, 1u); } for (int i = 0; i < decControl.nChannelsInternal; i++) { Arrays.MemSetInt(channel_state[i].LBRR_flags, 0, 3); if (channel_state[i].LBRR_flag == 0) { continue; } if (channel_state[i].nFramesPerPacket == 1) { channel_state[i].LBRR_flags[0] = 1; continue; } int a = psRangeDec.dec_icdf(frameData, Tables.silk_LBRR_flags_iCDF_ptr[channel_state[i].nFramesPerPacket - 2], 8u) + 1; for (int j = 0; j < channel_state[i].nFramesPerPacket; j++) { channel_state[i].LBRR_flags[j] = Inlines.silk_RSHIFT(a, j) & 1; } } if (lostFlag == 0) { for (int j = 0; j < channel_state[0].nFramesPerPacket; j++) { for (int i = 0; i < decControl.nChannelsInternal; i++) { if (channel_state[i].LBRR_flags[j] == 0) { continue; } short[] pulses = new short[320]; if (decControl.nChannelsInternal == 2 && i == 0) { Stereo.silk_stereo_decode_pred(psRangeDec, frameData, array2); if (channel_state[1].LBRR_flags[j] == 0) { BoxedValueInt boxedValueInt2 = new BoxedValueInt(num); Stereo.silk_stereo_decode_mid_only(psRangeDec, frameData, boxedValueInt2); num = boxedValueInt2.Val; } } DecodeIndices.silk_decode_indices(condCoding: (j > 0 && channel_state[i].LBRR_flags[j - 1] != 0) ? 2 : 0, psDec: channel_state[i], psRangeDec: psRangeDec, frameData: frameData, FrameIndex: j, decode_LBRR: 1); DecodePulses.silk_decode_pulses(psRangeDec, frameData, pulses, channel_state[i].indices.signalType, channel_state[i].indices.quantOffsetType, channel_state[i].frame_length); } } } } if (decControl.nChannelsInternal == 2) { if (lostFlag == 0 || (lostFlag == 2 && channel_state[0].LBRR_flags[channel_state[0].nFramesDecoded] == 1)) { Stereo.silk_stereo_decode_pred(psRangeDec, frameData, array2); if ((lostFlag == 0 && channel_state[1].VAD_flags[channel_state[0].nFramesDecoded] == 0) || (lostFlag == 2 && channel_state[1].LBRR_flags[channel_state[0].nFramesDecoded] == 0)) { BoxedValueInt boxedValueInt3 = new BoxedValueInt(num); Stereo.silk_stereo_decode_mid_only(psRangeDec, frameData, boxedValueInt3); num = boxedValueInt3.Val; } else { num = 0; } } else { for (int i = 0; i < 2; i++) { array2[i] = psDec.sStereo.pred_prev_Q13[i]; } } } if (decControl.nChannelsInternal == 2 && num == 0 && psDec.prev_decode_only_middle == 1) { Arrays.MemSetShort(psDec.channel_state[1].outBuf, 0, 480); Arrays.MemSetInt(psDec.channel_state[1].sLPC_Q14_buf, 0, 16); psDec.channel_state[1].lagPrev = 100; psDec.channel_state[1].LastGainIndex = 10; psDec.channel_state[1].prevSignalType = 0; psDec.channel_state[1].first_frame_after_reset = 1; } int num5 = ((decControl.internalSampleRate * decControl.nChannelsInternal < decControl.API_sampleRate * decControl.nChannelsAPI) ? 1 : 0); Span<short> span; if (num5 != 0) { span = samplesOut; array[0] = samplesOut_ptr; array[1] = samplesOut_ptr + channel_state[0].frame_length + 2; } else { span = new short[decControl.nChannelsInternal * (channel_state[0].frame_length + 2)]; array[0] = 0; array[1] = channel_state[0].frame_length + 2; } int num6 = ((lostFlag != 0) ? ((psDec.prev_decode_only_middle == 0 || (decControl.nChannelsInternal == 2 && lostFlag == 2 && channel_state[1].LBRR_flags[channel_state[1].nFramesDecoded] == 1)) ? 1 : 0) : ((num == 0) ? 1 : 0)); for (int i = 0; i < decControl.nChannelsInternal; i++) { if (i == 0 || num6 != 0) { int num7 = channel_state[0].nFramesDecoded - i; int condCoding2 = ((num7 > 0) ? ((lostFlag == 2) ? ((channel_state[i].LBRR_flags[num7 - 1] != 0) ? 2 : 0) : ((i > 0 && psDec.prev_decode_only_middle != 0) ? 1 : 2)) : 0); num2 += channel_state[i].silk_decode_frame(psRangeDec, frameData, span, array[i] + 2, boxedValueInt, lostFlag, condCoding2); } else { Arrays.MemSetWithOffset<short>(span, 0, array[i] + 2, boxedValueInt.Val); } channel_state[i].nFramesDecoded++; } if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 2) { Stereo.silk_stereo_MS_to_LR(psDec.sStereo, span, array[0], span, array[1], array2, channel_state[0].fs_kHz, boxedValueInt.Val); } else { psDec.sStereo.sMid.AsSpan(0, 2).CopyTo(span.Slice(array[0])); span.Slice(array[0] + boxedValueInt.Val, 2).CopyTo(psDec.sStereo.sMid); } nSamplesOut = Inlines.silk_DIV32(boxedValueInt.Val * decControl.API_sampleRate, Inlines.silk_SMULBB(channel_state[0].fs_kHz, 1000)); Span<short> output; int num8; if (decControl.nChannelsAPI == 2) { output = new short[nSamplesOut]; num8 = 0; } else { output = samplesOut; num8 = samplesOut_ptr; } if (num5 != 0) { short[] array3 = new short[decControl.nChannelsInternal * (channel_state[0].frame_length + 2)]; samplesOut.Slice(samplesOut_ptr, decControl.nChannelsInternal * (channel_state[0].frame_length + 2)).CopyTo(array3); span = array3; array[0] = 0; array[1] = channel_state[0].frame_length + 2; } for (int i = 0; i < Inlines.silk_min(decControl.nChannelsAPI, decControl.nChannelsInternal); i++) { num2 += Resampler.silk_resampler(channel_state[i].resampler_state, output, num8, span, array[i] + 1, boxedValueInt.Val); if (decControl.nChannelsAPI == 2) { int num9 = samplesOut_ptr + i; for (int j = 0; j < nSamplesOut; j++) { samplesOut[num9 + 2 * j] = output[num8 + j]; } } } if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 1) { if (num3 != 0) { num2 += Resampler.silk_resampler(channel_state[1].resampler_state, output, num8, span, array[0] + 1, boxedValueInt.Val); for (int j = 0; j < nSamplesOut; j++) { samplesOut[samplesOut_ptr + 1 + 2 * j] = output[num8 + j]; } } else { for (int j = 0; j < nSamplesOut; j++) { samplesOut[samplesOut_ptr + 1 + 2 * j] = samplesOut[samplesOut_ptr + 2 * j]; } } } if (channel_state[0].prevSignalType == 2) { int[] array4 = new int[3] { 6, 4, 3 }; decControl.prevPitchLag = channel_state[0].lagPrev * array4[channel_state[0].fs_kHz - 8 >> 2]; } else { decControl.prevPitchLag = 0; } if (lostFlag == 1) { for (int j = 0; j < psDec.nChannelsInternal; j++) { psDec.channel_state[j].LastGainIndex = 10; } } else { psDec.prev_decode_only_middle = num; } return num2; } } internal static class DecodeCore { internal static void silk_decode_core(SilkChannelDecoder psDec, SilkDecoderControl psDecCtrl, Span<short> xq, int xq_ptr, short[] pulses) { int num = 0; short[] lTPCoef_Q = psDecCtrl.LTPCoef_Q14; short[] array = new short[psDec.ltp_mem_length]; int[] array2 = new int[psDec.ltp_mem_length + psDec.frame_length]; int[] array3 = new int[psDec.subfr_length]; int[] array4 = new int[psDec.subfr_length + 16]; int num2 = Tables.silk_Quantization_Offsets_Q10[psDec.indices.signalType >> 1][psDec.indices.quantOffsetType]; int num3 = ((psDec.indices.NLSFInterpCoef_Q2 < 4) ? 1 : 0); int seed = psDec.indices.Seed; for (int i = 0; i < psDec.frame_length; i++) { seed = Inlines.silk_RAND(seed); psDec.exc_Q14[i] = Inlines.silk_LSHIFT(pulses[i], 14); if (psDec.exc_Q14[i] > 0) { psDec.exc_Q14[i] -= 1280; } else if (psDec.exc_Q14[i] < 0) { psDec.exc_Q14[i] += 1280; } psDec.exc_Q14[i] += num2 << 4; if (seed < 0) { psDec.exc_Q14[i] = -psDec.exc_Q14[i]; } seed = Inlines.silk_ADD32_ovflw(seed, pulses[i]); } Arrays.MemCopy(psDec.sLPC_Q14_buf, 0, array4, 0, 16); int num4 = 0; int num5 = xq_ptr; int num6 = psDec.ltp_mem_length; for (int j = 0; j < psDec.nb_subfr; j++) { int[] array5 = array3; int num7 = 0; short[] array6 = psDecCtrl.PredCoef_Q12[j >> 1]; int num8 = j * 5; int num9 = psDec.indices.signalType; int b = Inlines.silk_RSHIFT(psDecCtrl.Gains_Q16[j], 6); int a = Inlines.silk_INVERSE32_varQ(psDecCtrl.Gains_Q16[j], 47); int num10; if (psDecCtrl.Gains_Q16[j] != psDec.prev_gain_Q16) { num10 = Inlines.silk_DIV32_varQ(psDec.prev_gain_Q16, psDecCtrl.Gains_Q16[j], 16); for (int i = 0; i < 16; i++) { array4[i] = Inlines.silk_SMULWW(num10, array4[i]); } } else { num10 = 65536; } psDec.prev_gain_Q16 = psDecCtrl.Gains_Q16[j]; if (psDec.lossCnt != 0 && psDec.prevSignalType == 2 && psDec.indices.signalType != 2 && j < 2) { Arrays.MemSetWithOffset(lTPCoef_Q, (short)0, num8, 5); lTPCoef_Q[num8 + 2] = 4096; num9 = 2; psDecCtrl.pitchL[j] = psDec.lagPrev; } if (num9 == 2) { num = psDecCtrl.pitchL[j]; if (j == 0 || (j == 2 && num3 != 0)) { int num11 = psDec.ltp_mem_length - num - psDec.LPC_order - 2; if (j == 2) { xq.Slice(xq_ptr, 2 * psDec.subfr_length).CopyTo(psDec.outBuf.AsSpan(psDec.ltp_mem_length)); } Filters.silk_LPC_analysis_filter(array, num11, psDec.outBuf, num11 + j * psDec.subfr_length, array6, 0, psDec.ltp_mem_length - num11, psDec.LPC_order); if (j == 0) { a = Inlines.silk_LSHIFT(Inlines.silk_SMULWB(a, psDecCtrl.LTP_scale_Q14), 2); } for (int i = 0; i < num + 2; i++) { array2[num6 - i - 1] = Inlines.silk_SMULWB(a, array[psDec.ltp_mem_length - i - 1]); } } else if (num10 != 65536) { for (int i = 0; i < num + 2; i++) { array2[num6 - i - 1] = Inlines.silk_SMULWW(num10, array2[num6 - i - 1]); } } } if (num9 == 2) { int num12 = num6 - num + 2; for (int i = 0; i < psDec.subfr_length; i++) { int a2 = 2; a2 = Inlines.silk_SMLAWB(a2, array2[num12], lTPCoef_Q[num8]); a2 = Inlines.silk_SMLAWB(a2, array2[num12 - 1], lTPCoef_Q[num8 + 1]); a2 = Inlines.silk_SMLAWB(a2, array2[num12 - 2], lTPCoef_Q[num8 + 2]); a2 = Inlines.silk_SMLAWB(a2, array2[num12 - 3], lTPCoef_Q[num8 + 3]); a2 = Inlines.silk_SMLAWB(a2, array2[num12 - 4], lTPCoef_Q[num8 + 4]); num12++; array5[num7 + i] = Inlines.silk_ADD_LSHIFT32(psDec.exc_Q14[num4 + i], a2, 1); array2[num6] = Inlines.silk_LSHIFT(array5[num7 + i], 1); num6++; } } else { array5 = psDec.exc_Q14; num7 = num4; } for (int i = 0; i < psDec.subfr_length; i++) { int a3 = Inlines.silk_RSHIFT(psDec.LPC_order, 1); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 1], array6[0]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 2], array6[1]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 3], array6[2]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 4], array6[3]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 5], array6[4]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 6], array6[5]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 7], array6[6]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 8], array6[7]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 9], array6[8]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 10], array6[9]); if (psDec.LPC_order == 16) { a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 11], array6[10]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 12], array6[11]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 13], array6[12]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 14], array6[13]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 15], array6[14]); a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 16], array6[15]); } array4[16 + i] = Inlines.silk_ADD_LSHIFT32(array5[num7 + i], a3, 4); xq[num5 + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(array4[16 + i], b), 8)); } Arrays.MemCopy(array4, psDec.subfr_length, array4, 0, 16); num4 += psDec.subfr_length; num5 += psDec.subfr_length; } Arrays.MemCopy(array4, 0, psDec.sLPC_Q14_buf, 0, 16); } } internal static class DecodeIndices { internal static void silk_decode_indices(SilkChannelDecoder psDec, EntropyCoder psRangeDec, ReadOnlySpan<byte> frameData, int FrameIndex, int decode_LBRR, int condCoding) { short[] array = new short[psDec.LPC_order]; byte[] array2 = new byte[psDec.LPC_order]; int num = ((decode_LBRR == 0 && psDec.VAD_flags[FrameIndex] == 0) ? psRangeDec.dec_icdf(frameData, Tables.silk_type_offset_no_VAD_iCDF, 8u) : (psRangeDec.dec_icdf(frameData, Tables.silk_type_offset_VAD_iCDF, 8u) + 2)); psDec.indices.signalType = (sbyte)Inlines.silk_RSHIFT(num, 1); psDec.indices.quantOffsetType = (sbyte)(num & 1); if (condCoding == 2) { psDec.indices.GainsIndices[0] = (sbyte)psRangeDec.dec_icdf(frameData, Tables.silk_delta_gain_iCDF, 8u); } else { psDec.indices.GainsIndices[0] = (sbyte)Inlines.silk_LSHIFT(psRangeDec.dec_icdf(frameData, Tables.silk_gain_iCDF[psDec.indices.signalType], 8u), 3); psDec.indices.GainsIndices[0] += (sbyte)psRangeDec.dec_icdf(frameData, Tables.silk_uniform8_iCDF, 8u); } for (int i = 1; i < psDec.nb_subfr; i++) { psDec.indices.GainsIndices[i] = (sbyte)psRangeDec.dec_icdf(frameData, Tables.silk_delta_gain_iCDF, 8u); } psDec.indices.NLSFIndices[0] = (sbyte)psRangeDec.dec_icdf(frameData, psDec.psNLSF_CB.CB1_iCDF, (psDec.indices.signalType >> 1) * psDec.psNLSF_CB.nVectors, 8u); NLSF.silk_NLSF_unpack(array, array2, psDec.psNLSF_CB, psDec.indices.NLSFIndices[0]); for (int i = 0; i < psDec.psNLSF_CB.order; i++) { num = psRangeDec.dec_icdf(frameData, psDec.psNLSF_CB.ec_iCDF, array[i], 8u); switch (num) { case 0: num -= psRangeDec.dec_icdf(frameData, Tables.silk_NLSF_EXT_iCDF, 8u); break; case 8: num += psRangeDec.dec_icdf(frameData, Tables.silk_NLSF_EXT_iCDF, 8u); break; } psDec.indices.NLSFIndices[i + 1] = (sbyte)(num - 4); } if (psDec.nb_subfr == 4) { psDec.indices.NLSFInterpCoef_Q2 = (sbyte)psRangeDec.dec_icdf(frameData, Tables.silk_NLSF
plugins/Concentus.Oggfile.dll
Decompiled 3 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using Concentus.Structs; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTrademark("")] [assembly: NeutralResourcesLanguage("en")] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Logan Stromberg")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © Logan Stromberg, Andrew Ward")] [assembly: AssemblyDescription("This package implements file streams which can be used to extract or encode Opus packets in an Ogg-formatted audio file (usually .opus), giving developers a very simple API to perform the task of reading or writing audio files that can be played universally. The Concentus library is used to encode/decode the opus packets automatically. The codec can optionally be accelerated by also referencing the Concentus.Native package.")] [assembly: AssemblyFileVersion("1.0.7.0")] [assembly: AssemblyInformationalVersion("1.0.7.0+27c3125205ddcd891822a398284b246636fafb94")] [assembly: AssemblyProduct("Concentus.Oggfile")] [assembly: AssemblyTitle("Concentus.Oggfile")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/lostromb/concentus.oggfile")] [assembly: AssemblyVersion("1.0.7.0")] namespace Concentus.Oggfile; internal static class BinaryHelpers { internal static void Int16ToByteArrayLittleEndian(short val, byte[] target, int targetOffset) { UInt16ToByteArrayLittleEndian((ushort)val, target, targetOffset); } internal static void UInt16ToByteArrayLittleEndian(ushort val, byte[] target, int targetOffset) { target[targetOffset + 1] = (byte)((uint)(val >> 8) & 0xFFu); target[targetOffset] = (byte)(val & 0xFFu); } internal static void Int16ToByteSpanLittleEndian(short val, ref Span<byte> target) { UInt16ToByteArraySpanEndian((ushort)val, ref target); } internal static void UInt16ToByteArraySpanEndian(ushort val, ref Span<byte> target) { target[1] = (byte)((uint)(val >> 8) & 0xFFu); target[0] = (byte)(val & 0xFFu); } internal static void Int16ToByteArrayBigEndian(short val, byte[] target, int targetOffset) { UInt16ToByteArrayBigEndian((ushort)val, target, targetOffset); } internal static void UInt16ToByteArrayBigEndian(ushort val, byte[] target, int targetOffset) { target[targetOffset] = (byte)((uint)(val >> 8) & 0xFFu); target[targetOffset + 1] = (byte)(val & 0xFFu); } internal static void Int16ToByteSpanBigEndian(short val, ref Span<byte> target) { UInt16ToByteSpanBigEndian((ushort)val, ref target); } internal static void UInt16ToByteSpanBigEndian(ushort val, ref Span<byte> target) { target[0] = (byte)((uint)(val >> 8) & 0xFFu); target[1] = (byte)(val & 0xFFu); } internal static void Int32ToByteArrayLittleEndian(int val, byte[] target, int targetOffset) { UInt32ToByteArrayLittleEndian((uint)val, target, targetOffset); } internal static void UInt32ToByteArrayLittleEndian(uint val, byte[] target, int targetOffset) { target[targetOffset + 3] = (byte)((val >> 24) & 0xFFu); target[targetOffset + 2] = (byte)((val >> 16) & 0xFFu); target[targetOffset + 1] = (byte)((val >> 8) & 0xFFu); target[targetOffset] = (byte)(val & 0xFFu); } internal static void Int32ToByteSpanLittleEndian(int val, ref Span<byte> target) { UInt32ToByteSpanLittleEndian((uint)val, ref target); } internal static void UInt32ToByteSpanLittleEndian(uint val, ref Span<byte> target) { target[3] = (byte)((val >> 24) & 0xFFu); target[2] = (byte)((val >> 16) & 0xFFu); target[1] = (byte)((val >> 8) & 0xFFu); target[0] = (byte)(val & 0xFFu); } internal static void UInt24ToByteArrayBigEndian(uint val, byte[] target, int targetOffset) { target[targetOffset] = (byte)((val >> 16) & 0xFFu); target[targetOffset + 1] = (byte)((val >> 8) & 0xFFu); target[targetOffset + 2] = (byte)(val & 0xFFu); } internal static void UInt24ToByteSpanBigEndian(uint val, ref Span<byte> target) { target[0] = (byte)((val >> 16) & 0xFFu); target[1] = (byte)((val >> 8) & 0xFFu); target[2] = (byte)(val & 0xFFu); } internal static void Int32ToByteArrayBigEndian(int val, byte[] target, int targetOffset) { UInt32ToByteArrayBigEndian((uint)val, target, targetOffset); } internal static void UInt32ToByteArrayBigEndian(uint val, byte[] target, int targetOffset) { target[targetOffset] = (byte)((val >> 24) & 0xFFu); target[targetOffset + 1] = (byte)((val >> 16) & 0xFFu); target[targetOffset + 2] = (byte)((val >> 8) & 0xFFu); target[targetOffset + 3] = (byte)(val & 0xFFu); } internal static void Int32ToByteSpanBigEndian(int val, ref Span<byte> target) { UInt32ToByteSpanBigEndian((uint)val, ref target); } internal static void UInt32ToByteSpanBigEndian(uint val, ref Span<byte> target) { target[0] = (byte)((val >> 24) & 0xFFu); target[1] = (byte)((val >> 16) & 0xFFu); target[2] = (byte)((val >> 8) & 0xFFu); target[3] = (byte)(val & 0xFFu); } internal static void Int64ToByteArrayLittleEndian(long val, byte[] target, int targetOffset) { UInt64ToByteArrayLittleEndian((ulong)val, target, targetOffset); } internal static void UInt64ToByteArrayLittleEndian(ulong val, byte[] target, int targetOffset) { target[targetOffset + 7] = (byte)((val >> 56) & 0xFF); target[targetOffset + 6] = (byte)((val >> 48) & 0xFF); target[targetOffset + 5] = (byte)((val >> 40) & 0xFF); target[targetOffset + 4] = (byte)((val >> 32) & 0xFF); target[targetOffset + 3] = (byte)((val >> 24) & 0xFF); target[targetOffset + 2] = (byte)((val >> 16) & 0xFF); target[targetOffset + 1] = (byte)((val >> 8) & 0xFF); target[targetOffset] = (byte)(val & 0xFF); } internal static void Int64ToByteSpanLittleEndian(long val, ref Span<byte> target) { UInt64ToByteSpanLittleEndian((ulong)val, ref target); } internal static void UInt64ToByteSpanLittleEndian(ulong val, ref Span<byte> target) { target[7] = (byte)((val >> 56) & 0xFF); target[6] = (byte)((val >> 48) & 0xFF); target[5] = (byte)((val >> 40) & 0xFF); target[4] = (byte)((val >> 32) & 0xFF); target[3] = (byte)((val >> 24) & 0xFF); target[2] = (byte)((val >> 16) & 0xFF); target[1] = (byte)((val >> 8) & 0xFF); target[0] = (byte)(val & 0xFF); } internal static void Int64ToByteArrayBigEndian(long val, byte[] target, int targetOffset) { UInt64ToByteArrayBigEndian((ulong)val, target, targetOffset); } internal static void UInt64ToByteArrayBigEndian(ulong val, byte[] target, int targetOffset) { target[targetOffset] = (byte)((val >> 56) & 0xFF); target[targetOffset + 1] = (byte)((val >> 48) & 0xFF); target[targetOffset + 2] = (byte)((val >> 40) & 0xFF); target[targetOffset + 3] = (byte)((val >> 32) & 0xFF); target[targetOffset + 4] = (byte)((val >> 24) & 0xFF); target[targetOffset + 5] = (byte)((val >> 16) & 0xFF); target[targetOffset + 6] = (byte)((val >> 8) & 0xFF); target[targetOffset + 7] = (byte)(val & 0xFF); } internal static void Int64ToByteSpanBigEndian(long val, ref Span<byte> target) { UInt64ToByteSpanBigEndian((ulong)val, ref target); } internal static void UInt64ToByteSpanBigEndian(ulong val, ref Span<byte> target) { target[0] = (byte)((val >> 56) & 0xFF); target[1] = (byte)((val >> 48) & 0xFF); target[2] = (byte)((val >> 40) & 0xFF); target[3] = (byte)((val >> 32) & 0xFF); target[4] = (byte)((val >> 24) & 0xFF); target[5] = (byte)((val >> 16) & 0xFF); target[6] = (byte)((val >> 8) & 0xFF); target[7] = (byte)(val & 0xFF); } internal static short ByteArrayToInt16LittleEndian(byte[] source, int offset) { return (short)((short)(0 | (short)(source[offset + 1] << 8)) | (short)source[offset]); } internal static short ByteSpanToInt16LittleEndian(ref Span<byte> source) { return (short)((short)(0 | (short)(source[1] << 8)) | (short)source[0]); } internal static short ByteSpanToInt16LittleEndian(ref ReadOnlySpan<byte> source) { return (short)((short)(0 | (short)(source[1] << 8)) | (short)source[0]); } internal static ushort ByteArrayToUInt16LittleEndian(byte[] source, int offset) { return (ushort)((ushort)(0u | (ushort)(source[offset + 1] << 8)) | source[offset]); } internal static ushort ByteSpanToUInt16LittleEndian(ref Span<byte> source) { return (ushort)((ushort)(0u | (ushort)(source[1] << 8)) | source[0]); } internal static ushort ByteSpanToUInt16LittleEndian(ref ReadOnlySpan<byte> source) { return (ushort)((ushort)(0u | (ushort)(source[1] << 8)) | source[0]); } internal static short ByteArrayToInt16BigEndian(byte[] source, int offset) { return (short)((short)(0 | (short)(source[offset] << 8)) | (short)source[offset + 1]); } internal static short ByteSpanToInt16BigEndian(ref Span<byte> source) { return (short)((short)(0 | (short)(source[0] << 8)) | (short)source[1]); } internal static short ByteSpanToInt16BigEndian(ref ReadOnlySpan<byte> source) { return (short)((short)(0 | (short)(source[0] << 8)) | (short)source[1]); } internal static ushort ByteArrayToUInt16BigEndian(byte[] source, int offset) { return (ushort)((ushort)(0u | (ushort)(source[offset] << 8)) | source[offset + 1]); } internal static ushort ByteSpanToUInt16BigEndian(ref Span<byte> source) { return (ushort)((ushort)(0u | (ushort)(source[0] << 8)) | source[1]); } internal static ushort ByteSpanToUInt16BigEndian(ref ReadOnlySpan<byte> source) { return (ushort)((ushort)(0u | (ushort)(source[0] << 8)) | source[1]); } internal static int ByteArrayToInt32LittleEndian(byte[] source, int offset) { return 0 | (source[offset + 3] << 24) | (source[offset + 2] << 16) | (source[offset + 1] << 8) | source[offset]; } internal static int ByteSpanToInt32LittleEndian(ref Span<byte> source) { return 0 | (source[3] << 24) | (source[2] << 16) | (source[1] << 8) | source[0]; } internal static int ByteSpanToInt32LittleEndian(ref ReadOnlySpan<byte> source) { return 0 | (source[3] << 24) | (source[2] << 16) | (source[1] << 8) | source[0]; } internal static uint ByteArrayToUInt32LittleEndian(byte[] source, int offset) { return 0u | (uint)(source[offset + 3] << 24) | (uint)(source[offset + 2] << 16) | (uint)(source[offset + 1] << 8) | source[offset]; } internal static uint ByteSpanToUInt32LittleEndian(ref Span<byte> source) { return 0u | (uint)(source[3] << 24) | (uint)(source[2] << 16) | (uint)(source[1] << 8) | source[0]; } internal static uint ByteSpanToUInt32LittleEndian(ref ReadOnlySpan<byte> source) { return 0u | (uint)(source[3] << 24) | (uint)(source[2] << 16) | (uint)(source[1] << 8) | source[0]; } internal static uint ByteArrayToUInt24BigEndian(byte[] source, int offset) { return 0u | (uint)(source[offset] << 16) | (uint)(source[offset + 1] << 8) | source[offset + 2]; } internal static uint ByteSpanToUInt24BigEndian(ref Span<byte> source) { return 0u | (uint)(source[0] << 16) | (uint)(source[1] << 8) | source[2]; } internal static uint ByteSpanToUInt24BigEndian(ref ReadOnlySpan<byte> source) { return 0u | (uint)(source[0] << 16) | (uint)(source[1] << 8) | source[2]; } internal static int ByteArrayToInt32BigEndian(byte[] source, int offset) { return 0 | (source[offset] << 24) | (source[offset + 1] << 16) | (source[offset + 2] << 8) | source[offset + 3]; } internal static int ByteSpanToInt32BigEndian(ref Span<byte> source) { return 0 | (source[0] << 24) | (source[1] << 16) | (source[2] << 8) | source[3]; } internal static int ByteSpanToInt32BigEndian(ref ReadOnlySpan<byte> source) { return 0 | (source[0] << 24) | (source[1] << 16) | (source[2] << 8) | source[3]; } internal static uint ByteArrayToUInt32BigEndian(byte[] source, int offset) { return 0u | (uint)(source[offset] << 24) | (uint)(source[offset + 1] << 16) | (uint)(source[offset + 2] << 8) | source[offset + 3]; } internal static uint ByteSpanToUInt32BigEndian(ref Span<byte> source) { return 0u | (uint)(source[0] << 24) | (uint)(source[1] << 16) | (uint)(source[2] << 8) | source[3]; } internal static uint ByteSpanToUInt32BigEndian(ref ReadOnlySpan<byte> source) { return 0u | (uint)(source[0] << 24) | (uint)(source[1] << 16) | (uint)(source[2] << 8) | source[3]; } internal static long ByteArrayToInt64LittleEndian(byte[] source, int offset) { return (long)(0 | ((ulong)source[offset + 7] << 56) | ((ulong)source[offset + 6] << 48) | ((ulong)source[offset + 5] << 40) | ((ulong)source[offset + 4] << 32) | ((ulong)source[offset + 3] << 24) | ((ulong)source[offset + 2] << 16) | ((ulong)source[offset + 1] << 8) | source[offset]); } internal static long ByteSpanToInt64LittleEndian(ref Span<byte> source) { return (long)(0 | ((ulong)source[7] << 56) | ((ulong)source[6] << 48) | ((ulong)source[5] << 40) | ((ulong)source[4] << 32) | ((ulong)source[3] << 24) | ((ulong)source[2] << 16) | ((ulong)source[1] << 8) | source[0]); } internal static long ByteSpanToInt64LittleEndian(ref ReadOnlySpan<byte> source) { return (long)(0 | ((ulong)source[7] << 56) | ((ulong)source[6] << 48) | ((ulong)source[5] << 40) | ((ulong)source[4] << 32) | ((ulong)source[3] << 24) | ((ulong)source[2] << 16) | ((ulong)source[1] << 8) | source[0]); } internal static ulong ByteArrayToUInt64LittleEndian(byte[] source, int offset) { return 0 | ((ulong)source[offset + 7] << 56) | ((ulong)source[offset + 6] << 48) | ((ulong)source[offset + 5] << 40) | ((ulong)source[offset + 4] << 32) | ((ulong)source[offset + 3] << 24) | ((ulong)source[offset + 2] << 16) | ((ulong)source[offset + 1] << 8) | source[offset]; } internal static ulong ByteSpanToUInt64LittleEndian(ref Span<byte> source) { return 0 | ((ulong)source[7] << 56) | ((ulong)source[6] << 48) | ((ulong)source[5] << 40) | ((ulong)source[4] << 32) | ((ulong)source[3] << 24) | ((ulong)source[2] << 16) | ((ulong)source[1] << 8) | source[0]; } internal static ulong ByteSpanToUInt64LittleEndian(ref ReadOnlySpan<byte> source) { return 0 | ((ulong)source[7] << 56) | ((ulong)source[6] << 48) | ((ulong)source[5] << 40) | ((ulong)source[4] << 32) | ((ulong)source[3] << 24) | ((ulong)source[2] << 16) | ((ulong)source[1] << 8) | source[0]; } internal static long ByteArrayToInt64BigEndian(byte[] source, int offset) { return (long)(0 | ((ulong)source[offset] << 56) | ((ulong)source[offset + 1] << 48) | ((ulong)source[offset + 2] << 40) | ((ulong)source[offset + 3] << 32) | ((ulong)source[offset + 4] << 24) | ((ulong)source[offset + 5] << 16) | ((ulong)source[offset + 6] << 8) | source[offset + 7]); } internal static long ByteSpanToInt64BigEndian(ref Span<byte> source) { return (long)(0 | ((ulong)source[0] << 56) | ((ulong)source[1] << 48) | ((ulong)source[2] << 40) | ((ulong)source[3] << 32) | ((ulong)source[4] << 24) | ((ulong)source[5] << 16) | ((ulong)source[6] << 8) | source[7]); } internal static long ByteSpanToInt64BigEndian(ref ReadOnlySpan<byte> source) { return (long)(0 | ((ulong)source[0] << 56) | ((ulong)source[1] << 48) | ((ulong)source[2] << 40) | ((ulong)source[3] << 32) | ((ulong)source[4] << 24) | ((ulong)source[5] << 16) | ((ulong)source[6] << 8) | source[7]); } internal static ulong ByteArrayToUInt64BigEndian(byte[] source, int offset) { return 0 | ((ulong)source[offset] << 56) | ((ulong)source[offset + 1] << 48) | ((ulong)source[offset + 2] << 40) | ((ulong)source[offset + 3] << 32) | ((ulong)source[offset + 4] << 24) | ((ulong)source[offset + 5] << 16) | ((ulong)source[offset + 6] << 8) | source[offset + 7]; } internal static ulong ByteSpanToUInt64BigEndian(ref Span<byte> source) { return 0 | ((ulong)source[0] << 56) | ((ulong)source[1] << 48) | ((ulong)source[2] << 40) | ((ulong)source[3] << 32) | ((ulong)source[4] << 24) | ((ulong)source[5] << 16) | ((ulong)source[6] << 8) | source[7]; } internal static ulong ByteSpanToUInt64BigEndian(ref ReadOnlySpan<byte> source) { return 0 | ((ulong)source[0] << 56) | ((ulong)source[1] << 48) | ((ulong)source[2] << 40) | ((ulong)source[3] << 32) | ((ulong)source[4] << 24) | ((ulong)source[5] << 16) | ((ulong)source[6] << 8) | source[7]; } } internal class BufferedReadStream : Stream { private const int DEFAULT_INITIAL_SIZE = 32768; private const int DEFAULT_MAX_SIZE = 262144; private Stream _baseStream; private StreamReadBuffer _buffer; private long _readPosition; public bool CloseBaseStream { get; set; } public bool MinimalRead { get { return _buffer.MinimalRead; } set { _buffer.MinimalRead = value; } } public int MaxBufferSize { get { return _buffer.MaxSize; } set { CheckLock(); _buffer.MaxSize = value; } } public long BufferBaseOffset => _buffer.BaseOffset; public int BufferBytesFilled => _buffer.BytesFilled; public override bool CanRead => true; public override bool CanSeek => true; public override bool CanWrite => false; public override long Length => _baseStream.Length; public override long Position { get { return _readPosition; } set { Seek(value, SeekOrigin.Begin); } } public BufferedReadStream(Stream baseStream) : this(baseStream, 32768, 262144, minimalRead: false) { } public BufferedReadStream(Stream baseStream, bool minimalRead) : this(baseStream, 32768, 262144, minimalRead) { } public BufferedReadStream(Stream baseStream, int initialSize, int maxSize) : this(baseStream, initialSize, maxSize, minimalRead: false) { } public BufferedReadStream(Stream baseStream, int initialSize, int maxBufferSize, bool minimalRead) { if (baseStream == null) { throw new ArgumentNullException("baseStream"); } if (!baseStream.CanRead) { throw new ArgumentException("baseStream"); } if (maxBufferSize < 1) { maxBufferSize = 1; } if (initialSize < 1) { initialSize = 1; } if (initialSize > maxBufferSize) { initialSize = maxBufferSize; } _baseStream = baseStream; _buffer = new StreamReadBuffer(baseStream, initialSize, maxBufferSize, minimalRead); _buffer.MaxSize = maxBufferSize; _buffer.MinimalRead = minimalRead; } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { if (_buffer != null) { _buffer.Dispose(); _buffer = null; } _ = CloseBaseStream; } } public void TakeLock() { } private void CheckLock() { } public void ReleaseLock() { } public void Discard(int bytes) { CheckLock(); _buffer.DiscardThrough(_buffer.BaseOffset + bytes); } public void DiscardThrough(long offset) { CheckLock(); _buffer.DiscardThrough(offset); } public override void Flush() { } public override int ReadByte() { CheckLock(); int num = _buffer.ReadByte(Position); if (num > -1) { Seek(1L, SeekOrigin.Current); } return num; } public override int Read(byte[] buffer, int offset, int count) { CheckLock(); int num = _buffer.Read(Position, buffer, offset, count); Seek(num, SeekOrigin.Current); return num; } public override long Seek(long offset, SeekOrigin origin) { CheckLock(); switch (origin) { case SeekOrigin.Current: offset += Position; break; case SeekOrigin.End: offset += _baseStream.Length; break; } if (!_baseStream.CanSeek) { if (offset < _buffer.BaseOffset) { throw new InvalidOperationException("Cannot seek to before the start of the buffer!"); } if (offset > _buffer.BufferEndOffset) { throw new InvalidOperationException("Cannot seek to beyond the end of the buffer! Discard some bytes."); } } return _readPosition = offset; } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } } internal abstract class DataPacket { [Flags] protected enum PacketFlags : byte { IsResync = 1, IsEndOfStream = 2, IsShort = 4, HasGranuleCount = 8, User1 = 0x10, User2 = 0x20, User3 = 0x40, User4 = 0x80 } private ulong _bitBucket; private int _bitCount; private int _readBits; private byte _overflowBits; private PacketFlags _packetFlags; private long _granulePosition; private long _pageGranulePosition; private int _length; private int _granuleCount; private int _pageSequenceNumber; public bool IsResync { get { return GetFlag(PacketFlags.IsResync); } internal set { SetFlag(PacketFlags.IsResync, value); } } public long GranulePosition { get { return _granulePosition; } set { _granulePosition = value; } } public long PageGranulePosition { get { return _pageGranulePosition; } internal set { _pageGranulePosition = value; } } public int Length { get { return _length; } protected set { _length = value; } } public bool IsEndOfStream { get { return GetFlag(PacketFlags.IsEndOfStream); } internal set { SetFlag(PacketFlags.IsEndOfStream, value); } } public long BitsRead => _readBits; public int? GranuleCount { get { if (GetFlag(PacketFlags.HasGranuleCount)) { return _granuleCount; } return null; } set { if (value.HasValue) { _granuleCount = value.Value; SetFlag(PacketFlags.HasGranuleCount, value: true); } else { SetFlag(PacketFlags.HasGranuleCount, value: false); } } } internal int PageSequenceNumber { get { return _pageSequenceNumber; } set { _pageSequenceNumber = value; } } internal bool IsShort { get { return GetFlag(PacketFlags.IsShort); } private set { SetFlag(PacketFlags.IsShort, value); } } protected bool GetFlag(PacketFlags flag) { return (_packetFlags & flag) == flag; } protected void SetFlag(PacketFlags flag, bool value) { if (value) { _packetFlags |= flag; } else { _packetFlags &= (PacketFlags)(byte)(~(int)flag); } } protected DataPacket(int length) { Length = length; } protected abstract int ReadNextByte(); public virtual void Done() { } public ulong TryPeekBits(int count, out int bitsRead) { ulong num = 0uL; switch (count) { default: throw new ArgumentOutOfRangeException("count"); case 0: bitsRead = 0; return 0uL; case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63: case 64: break; } while (_bitCount < count) { int num2 = ReadNextByte(); if (num2 == -1) { bitsRead = _bitCount; num = _bitBucket; _bitBucket = 0uL; _bitCount = 0; IsShort = true; return num; } _bitBucket = (ulong)((long)(num2 & 0xFF) << _bitCount) | _bitBucket; _bitCount += 8; if (_bitCount > 64) { _overflowBits = (byte)(num2 >> 72 - _bitCount); } } num = _bitBucket; if (count < 64) { num &= (ulong)((1L << count) - 1); } bitsRead = count; return num; } public void SkipBits(int count) { if (count == 0) { return; } if (_bitCount > count) { if (count > 63) { _bitBucket = 0uL; } else { _bitBucket >>= count; } if (_bitCount > 64) { int num = _bitCount - 64; _bitBucket |= (ulong)_overflowBits << _bitCount - count - num; if (num > count) { _overflowBits = (byte)(_overflowBits >> count); } } _bitCount -= count; _readBits += count; return; } if (_bitCount == count) { _bitBucket = 0uL; _bitCount = 0; _readBits += count; return; } count -= _bitCount; _readBits += _bitCount; _bitCount = 0; _bitBucket = 0uL; while (count > 8) { if (ReadNextByte() == -1) { count = 0; IsShort = true; break; } count -= 8; _readBits += 8; } if (count > 0) { int num2 = ReadNextByte(); if (num2 == -1) { IsShort = true; return; } _bitBucket = (ulong)(num2 >> count); _bitCount = 8 - count; _readBits += count; } } protected void ResetBitReader() { _bitBucket = 0uL; _bitCount = 0; _readBits = 0; IsShort = false; } public ulong ReadBits(int count) { if (count == 0) { return 0uL; } int bitsRead; ulong result = TryPeekBits(count, out bitsRead); SkipBits(count); return result; } public byte PeekByte() { int bitsRead; return (byte)TryPeekBits(8, out bitsRead); } public byte ReadByte() { return (byte)ReadBits(8); } public byte[] ReadBytes(int count) { List<byte> list = new List<byte>(count); while (list.Count < count) { list.Add(ReadByte()); } return list.ToArray(); } public int Read(byte[] buffer, int index, int count) { if (index < 0 || index + count > buffer.Length) { throw new ArgumentOutOfRangeException("index"); } for (int i = 0; i < count; i++) { int bitsRead; byte b = (byte)TryPeekBits(8, out bitsRead); if (bitsRead == 0) { return i; } buffer[index++] = b; SkipBits(8); } return count; } public bool ReadBit() { return ReadBits(1) == 1; } public short ReadInt16() { return (short)ReadBits(16); } public int ReadInt32() { return (int)ReadBits(32); } public long ReadInt64() { return (long)ReadBits(64); } public ushort ReadUInt16() { return (ushort)ReadBits(16); } public uint ReadUInt32() { return (uint)ReadBits(32); } public ulong ReadUInt64() { return ReadBits(64); } public void SkipBytes(int count) { SkipBits(count * 8); } } internal interface IContainerReader : IDisposable { int[] StreamSerials { get; } bool CanSeek { get; } long WasteBits { get; } int PagesRead { get; } event EventHandler<NewStreamEventArgs> NewStream; bool Init(); bool FindNextStream(); int GetTotalPageCount(); } internal interface IPacketProvider : IDisposable { int StreamSerial { get; } bool CanSeek { get; } long ContainerBits { get; } event EventHandler<ParameterChangeEventArgs> ParameterChange; int GetTotalPageCount(); DataPacket GetNextPacket(); DataPacket PeekNextPacket(); DataPacket GetPacket(int packetIndex); long GetGranuleCount(); DataPacket FindPacket(long granulePos, Func<DataPacket, DataPacket, int> packetGranuleCountCallback); void SeekToPacket(DataPacket packet, int preRoll); } internal 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; } } internal class OggContainerReader : 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 BufferedReadStream _stream; private Dictionary<int, PacketReader> _packetReaders; private List<int> _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 => _stream.CanSeek; public long WasteBits => _wasteBits; public event EventHandler<NewStreamEventArgs> NewStream; public OggContainerReader(Stream stream, bool closeOnDispose) { _packetReaders = new Dictionary<int, PacketReader>(); _disposedStreamSerials = new List<int>(); _stream = (stream as BufferedReadStream) ?? new BufferedReadStream(stream) { CloseBaseStream = closeOnDispose }; } public bool Init() { _stream.TakeLock(); try { return GatherNextPage() != -1; } finally { _stream.ReleaseLock(); } } 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() { if (!CanSeek) { throw new InvalidOperationException(); } int count = _packetReaders.Count; while (_packetReaders.Count == count) { _stream.TakeLock(); try { if (GatherNextPage() == -1) { break; } } finally { _stream.ReleaseLock(); } } return count > _packetReaders.Count; } public int GetTotalPageCount() { if (!CanSeek) { throw new InvalidOperationException(); } while (true) { _stream.TakeLock(); try { if (GatherNextPage() == -1) { break; } } finally { _stream.ReleaseLock(); } } 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<int> list = new List<int>(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 && _stream.ReadByte() == 103 && _stream.ReadByte() == 83) { num += num3; goto end_IL_0032; } _stream.Seek(-3L, 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<NewStreamEventArgs> newStream = this.NewStream; if (newStream == null) { break; } NewStreamEventArgs newStreamEventArgs = new NewStreamEventArgs(_packetReaders[pageHeader.StreamSerial]); newStream(this, newStreamEventArgs); if (!newStreamEventArgs.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.TakeLock(); try { _stream.Position = offset; return _stream.ReadByte(); } finally { _stream.ReleaseLock(); } } internal void PacketDiscardThrough(long offset) { _stream.TakeLock(); try { _stream.DiscardThrough(offset); } finally { _stream.ReleaseLock(); } } internal void GatherNextPage(int streamSerial) { if (!_packetReaders.ContainsKey(streamSerial)) { throw new ArgumentOutOfRangeException("streamSerial"); } int num; do { _stream.TakeLock(); try { if (_packetReaders[streamSerial].HasEndOfStream) { break; } num = GatherNextPage(); if (num != -1) { continue; } foreach (KeyValuePair<int, PacketReader> packetReader in _packetReaders) { if (!packetReader.Value.HasEndOfStream) { packetReader.Value.SetEndOfStream(); } } break; } finally { _stream.ReleaseLock(); } } while (num != streamSerial); } } internal class Crc { private const uint CRC32_POLY = 79764919u; private static uint[] crcTable; private uint _crc; public uint Value => _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) ^ ((num2 >= 2147483648u) ? 79764919u : 0u); } 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 OggContainerReader _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(OggContainerReader 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; } public override void Done() { if (_mergedPacket != null) { _mergedPacket.Done(); } else { _containerReader.PacketDiscardThrough(_offset + _length); } } } [DebuggerTypeProxy(typeof(DebugView))] internal class PacketReader : IPacketProvider, IDisposable { internal class DebugView { private PacketReader _reader; private Packet _last; private Packet _first; private Packet[] _packetList = new Packet[0]; public OggContainerReader 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<Packet> list = new List<Packet>(); 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 OggContainerReader _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 => _container.CanSeek; public event EventHandler<ParameterChangeEventArgs> ParameterChange; internal PacketReader(OggContainerReader container, int streamSerial) { _container = container; _streamSerial = streamSerial; } public void Dispose() { _eosFound = true; _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() { if (!CanSeek) { throw new InvalidOperationException(); } 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 (!CanSeek) { throw new InvalidOperationException(); } 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<DataPacket, DataPacket, int> 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<DataPacket, DataPacket, int> 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 } internal class OpusHeader { private byte version; private byte channel_count; private ushort pre_skip; private uint input_sample_rate; private short output_gain; private byte mapping_family; private byte stream_count; private byte coupled_count; } public class OpusOggReadStream { private const double GranuleSampleRate = 48000.0; private readonly Stream _stream; private readonly IOpusDecoder _decoder; private byte[] _nextDataPacket; private IPacketProvider _packetProvider; private bool _endOfStream; private OggContainerReader _containerReader; public bool CanSeek => _stream.CanSeek; public OpusTags Tags { get; private set; } public bool HasNextPacket => !_endOfStream; public string LastError { get; private set; } public long PageGranulePosition { get; private set; } public TimeSpan CurrentTime => TimeSpan.FromSeconds((double)PageGranulePosition / 48000.0); public long GranuleCount { get; private set; } public TimeSpan TotalTime => TimeSpan.FromSeconds((double)GranuleCount / 48000.0); public long PagePosition { get; private set; } public long PageCount { get; private set; } public OpusOggReadStream(IOpusDecoder decoder, Stream stream) { if (stream == null) { throw new ArgumentNullException("stream"); } _stream = stream; _decoder = decoder; _endOfStream = !Initialize(); } public short[] DecodeNextPacket() { //IL_0091: Expected O, but got Unknown if (_decoder == null) { throw new InvalidOperationException("Cannot decode opus packets as a decoder was never provided"); } if (_nextDataPacket == null || _nextDataPacket.Length == 0) { _endOfStream = true; return null; } try { int numSamples = OpusPacketInfo.GetNumSamples((ReadOnlySpan<byte>)_nextDataPacket.AsSpan(), _decoder.SampleRate); short[] array = new short[numSamples * _decoder.NumChannels]; _decoder.Decode((ReadOnlySpan<byte>)_nextDataPacket.AsSpan(), array.AsSpan(), numSamples, false); QueueNextPacket(); return array; } catch (OpusException val) { OpusException val2 = val; LastError = "Opus decoder threw exception: " + ((Exception)(object)val2).Message; return null; } } public byte[] ReadNextRawPacket() { if (_nextDataPacket == null || _nextDataPacket.Length == 0) { _endOfStream = true; return null; } byte[] nextDataPacket = _nextDataPacket; QueueNextPacket(); return nextDataPacket; } private bool Initialize() { try { OggContainerReader oggContainerReader = new OggContainerReader(_stream, closeOnDispose: true); if (!oggContainerReader.Init()) { LastError = "Could not initialize stream"; oggContainerReader.Dispose(); return false; } if (oggContainerReader.StreamSerials.Length == 0) { LastError = "Initialization failed: No elementary streams found in input file"; oggContainerReader.Dispose(); return false; } _containerReader = oggContainerReader; int streamSerial = oggContainerReader.StreamSerials[0]; _packetProvider = oggContainerReader.GetStream(streamSerial); if (CanSeek) { GranuleCount = _packetProvider.GetGranuleCount(); PageCount = _packetProvider.GetTotalPageCount(); } QueueNextPacket(); return true; } catch (Exception ex) { LastError = "Unknown initialization error: " + ex.Message; return false; } } public void SeekTo(TimeSpan playbackTime) { if (!CanSeek) { throw new InvalidOperationException("Stream is not seekable."); } if (playbackTime < TimeSpan.Zero || playbackTime > TotalTime) { throw new ArgumentOutOfRangeException("playbackTime"); } long granulePosition = Convert.ToInt64(playbackTime.TotalSeconds * 48000.0); SeekToGranulePosition(granulePosition); } private void SeekToGranulePosition(long granulePosition) { if (!CanSeek) { throw new InvalidOperationException("Stream is not seekable."); } if (granulePosition < 0 || granulePosition > GranuleCount) { throw new ArgumentOutOfRangeException("granulePosition"); } DataPacket dataPacket = _packetProvider.FindPacket(granulePosition, GetPacketLength); if (dataPacket == null || dataPacket.IsEndOfStream) { _endOfStream = true; _nextDataPacket = null; return; } _packetProvider.SeekToPacket(dataPacket, 1); PageGranulePosition = _packetProvider.PeekNextPacket().PageGranulePosition; if (_decoder != null) { _decoder.ResetState(); } } private int GetPacketLength(DataPacket curPacket, DataPacket lastPacket) { if (lastPacket == null || curPacket.IsResync) { return 0; } if (curPacket.ReadBit()) { return 0; } if (lastPacket.ReadBit()) { return 0; } return 1; } private void QueueNextPacket() { if (_endOfStream) { return; } DataPacket nextPacket = _packetProvider.GetNextPacket(); if (nextPacket == null) { _endOfStream = true; _nextDataPacket = null; return; } PageGranulePosition = nextPacket.PageGranulePosition; PagePosition = nextPacket.PageSequenceNumber; byte[] array = new byte[nextPacket.Length]; nextPacket.Read(array, 0, nextPacket.Length); nextPacket.Done(); if (array.Length > 8 && "OpusHead".Equals(Encoding.UTF8.GetString(array, 0, 8))) { QueueNextPacket(); } else if (array.Length > 8 && "OpusTags".Equals(Encoding.UTF8.GetString(array, 0, 8))) { Tags = OpusTags.ParsePacket(array, array.Length); QueueNextPacket(); } else { _nextDataPacket = array; } } public void Close() { _containerReader?.Dispose(); } } public class OpusOggWriteStream { private const int FRAME_SIZE_MS = 20; private const byte EARLY_FINALIZE_SEGMENT_LIMIT = 248; private IOpusEncoder _encoder; private Stream _outputStream; private Crc _crc; private int _inputChannels; private IResampler _resampler; private int _inputSampleRate; private readonly bool _leaveOpen; private int _encoderSampleRate; private short[] _opusFrame; private int _opusFrameSamples; private int _opusFrameIndex; private byte[] _currentHeader = new byte[400]; private byte[] _currentPayload = new byte[65536]; private int _headerIndex; private int _payloadIndex; private int _pageCounter; private int _logicalStreamId; private long _granulePosition; private byte _packetsInPage; private byte _lacingTableCount; private byte _maxPacketsPerPage = 248; private const int PAGE_FLAGS_POS = 5; private const int GRANULE_COUNT_POS = 6; private const int CHECKSUM_HEADER_POS = 22; private const int SEGMENT_COUNT_POS = 26; private bool _finalized; public TimeSpan MaxAudioLengthPerPage { get { return TimeSpan.FromMilliseconds(20 * _maxPacketsPerPage); } set { if (value <= TimeSpan.Zero) { throw new ArgumentOutOfRangeException("MaxAudioLengthPerPage"); } _maxPacketsPerPage = (byte)Math.Min(248, Math.Max(1, (int)(value.TotalMilliseconds / 20.0))); } } public OpusOggWriteStream(IOpusEncoder encoder, Stream outputStream, OpusTags fileTags = null, int inputSampleRate = 0, int resamplerQuality = 5, bool leaveOpen = false) { _encoder = encoder; if (_encoder.UseDTX) { throw new ArgumentException("DTX is not currently supported in Ogg streams"); } _inputSampleRate = inputSampleRate; _leaveOpen = leaveOpen; if (_inputSampleRate == 0) { _inputSampleRate = _encoder.SampleRate; } _logicalStreamId = new Random().Next(); _encoderSampleRate = encoder.SampleRate; _inputChannels = encoder.NumChannels; _outputStream = outputStream; _opusFrameIndex = 0; _granulePosition = 0L; _opusFrameSamples = (int)((long)_encoderSampleRate * 20L / 1000); _opusFrame = new short[_opusFrameSamples * _inputChannels]; _crc = new Crc(); _resampler = ResamplerFactory.CreateResampler(_inputChannels, _inputSampleRate, _encoderSampleRate, resamplerQuality, (TextWriter)null); BeginNewPage(); WriteOpusHeadPage(); WriteOpusTagsPage(fileTags); } public void WriteSamples(short[] data, int offset, int count) { if (_finalized) { throw new InvalidOperationException("Cannot write new samples to Ogg file, the output stream is already closed!"); } if (data.Length - offset < count) { throw new ArgumentOutOfRangeException("The given audio buffer claims to have " + count + " samples, but it actually only has " + (data.Length - offset)); } int num = 0; for (int num2 = Math.Min(_opusFrame.Length - _opusFrameIndex, count - num); num2 > 0; num2 = Math.Min(_opusFrame.Length - _opusFrameIndex, count - num)) { if (_inputSampleRate != _encoderSampleRate) { int num3 = (count - num) / _inputChannels; int num4 = num2 / _inputChannels; _resampler.ProcessInterleaved(data.AsSpan(offset + num), ref num3, _opusFrame.AsSpan(_opusFrameIndex), ref num4); num += num3 * _inputChannels; _opusFrameIndex += num4 * _inputChannels; } else { data.AsSpan(offset + num, num2).CopyTo(_opusFrame.AsSpan(_opusFrameIndex, num2)); _opusFrameIndex += num2; num += num2; } if (_opusFrameIndex == _opusFrame.Length) { int num5 = _encoder.Encode((ReadOnlySpan<short>)_opusFrame.AsSpan(), _opusFrameSamples, _currentPayload.AsSpan(_payloadIndex), _currentPayload.Length - _payloadIndex); _payloadIndex += num5; _granulePosition += 960L; int num6 = num5; while (num6 >= 255) { num6 -= 255; _currentHeader[_headerIndex++] = byte.MaxValue; _lacingTableCount++; } _currentHeader[_headerIndex++] = (byte)num6; _lacingTableCount++; _packetsInPage++; if (_packetsInPage >= _maxPacketsPerPage || _lacingTableCount > 248) { FinalizePage(); } _opusFrameIndex = 0; } } } public void WriteSamples(float[] data, int offset, int count) { if (_finalized) { throw new InvalidOperationException("Cannot write new samples to Ogg file, the output stream is already closed!"); } short[] array = new short[count]; for (int i = 0; i < count; i++) { array[i] = (short)(data[i + offset] * 32767f); } WriteSamples(array, 0, count); } public void Finish() { int num = _opusFrame.Length - _opusFrameIndex; short[] data = new short[num]; WriteSamples(data, 0, num); FinalizePage(); WriteStreamFinishedPage(); _outputStream.Flush(); if (!_leaveOpen) { _outputStream.Dispose(); } _finalized = true; } private void WriteStreamFinishedPage() { _currentHeader[_headerIndex++] = 0; _lacingTableCount++; _currentHeader[5] = 4; FinalizePage(); } private void WriteOpusHeadPage() { if (_payloadIndex != 0) { throw new InvalidOperationException("Must begin writing OpusHead on a new page!"); } _payloadIndex += WriteValueToByteBuffer("OpusHead", _currentPayload, _payloadIndex); _currentPayload[_payloadIndex++] = 1; _currentPayload[_payloadIndex++] = (byte)_inputChannels; short val = 0; _payloadIndex += WriteValueToByteBuffer(val, _currentPayload, _payloadIndex); _payloadIndex += WriteValueToByteBuffer(_encoderSampleRate, _currentPayload, _payloadIndex); short val2 = 0; _payloadIndex += WriteValueToByteBuffer(val2, _currentPayload, _payloadIndex); _currentPayload[_payloadIndex++] = 0; _currentHeader[_headerIndex++] = (byte)_payloadIndex; _lacingTableCount++; _currentHeader[5] = 2; FinalizePage(); } private void WriteOpusTagsPage(OpusTags tags = null) { if (tags == null) { tags = new OpusTags(); } if (string.IsNullOrEmpty(tags.Comment)) { tags.Comment = _encoder.GetVersionString(); } if (_payloadIndex != 0) { throw new InvalidOperationException("Must begin writing OpusTags on a new page!"); } _payloadIndex += WriteValueToByteBuffer("OpusTags", _currentPayload, _payloadIndex); int num = WriteValueToByteBuffer(tags.Comment, _currentPayload, _payloadIndex + 4); _payloadIndex += WriteValueToByteBuffer(num, _currentPayload, _payloadIndex); _payloadIndex += num; int payloadIndex = _payloadIndex; _payloadIndex += 4; int num2 = 0; foreach (KeyValuePair<string, string> field in tags.Fields) { if (!string.IsNullOrEmpty(field.Key) && !string.IsNullOrEmpty(field.Value)) { num = WriteValueToByteBuffer(field.Key + "=" + field.Value, _currentPayload, _payloadIndex + 4); _payloadIndex += WriteValueToByteBuffer(num, _currentPayload, _payloadIndex); _payloadIndex += num; num2++; } } WriteValueToByteBuffer(num2, _currentPayload, payloadIndex); int num3; for (num3 = _payloadIndex; num3 >= 255; num3 -= 255) { _currentHeader[_headerIndex++] = byte.MaxValue; _lacingTableCount++; } _currentHeader[_headerIndex++] = (byte)num3; _lacingTableCount++; FinalizePage(); } private void BeginNewPage() { _headerIndex = 0; _payloadIndex = 0; _packetsInPage = 0; _lacingTableCount = 0; _headerIndex += WriteValueToByteBuffer("OggS", _currentHeader, _headerIndex); _currentHeader[_headerIndex++] = 0; _currentHeader[_headerIndex++] = 0; _headerIndex += WriteValueToByteBuffer(_granulePosition, _currentHeader, _headerIndex); _headerIndex += WriteValueToByteBuffer(_logicalStreamId, _currentHeader, _headerIndex); _headerIndex += WriteValueToByteBuffer(_pageCounter, _currentHeader, _headerIndex); _currentHeader[_headerIndex++] = 0; _currentHeader[_headerIndex++] = 0; _currentHeader[_headerIndex++] = 0; _currentHeader[_headerIndex++] = 0; _currentHeader[_headerIndex++] = _lacingTableCount; _pageCounter++; } private void FinalizePage() { if (_finalized) { throw new InvalidOperationException("Cannot finalize page, the output stream is already closed!"); } if (_lacingTableCount != 0) { _currentHeader[26] = _lacingTableCount; WriteValueToByteBuffer(_granulePosition, _currentHeader, 6); _crc.Reset(); for (int i = 0; i < _headerIndex; i++) { _crc.Update(_currentHeader[i]); } for (int j = 0; j < _payloadIndex; j++) { _crc.Update(_currentPayload[j]); } WriteValueToByteBuffer(_crc.Value, _currentHeader, 22); _outputStream.Write(_currentHeader, 0, _headerIndex); _outputStream.Write(_currentPayload, 0, _payloadIndex); BeginNewPage(); } } private static int WriteValueToByteBuffer(int val, byte[] target, int targetOffset) { BinaryHelpers.Int32ToByteArrayLittleEndian(val, target, targetOffset); return 4; } private static int WriteValueToByteBuffer(long val, byte[] target, int targetOffset) { BinaryHelpers.Int64ToByteArrayLittleEndian(val, target, targetOffset); return 8; } private static int WriteValueToByteBuffer(uint val, byte[] target, int targetOffset) { BinaryHelpers.UInt32ToByteArrayLittleEndian(val, target, targetOffset); return 4; } private static int WriteValueToByteBuffer(short val, byte[] target, int targetOffset) { BinaryHelpers.Int16ToByteArrayLittleEndian(val, target, targetOffset); return 2; } private static int WriteValueToByteBuffer(string val, byte[] target, int targetOffset) { if (string.IsNullOrEmpty(val)) { return 0; } return Encoding.UTF8.GetBytes(val, 0, val.Length, target, targetOffset); } } public class OpusRawWriteStream { private Stream _outputStream; private Crc _crc; private int _inputChannels; private readonly bool _leaveOpen; private int _inputSampleRate; private byte[] _currentHeader = new byte[400]; private byte[] _currentPayload = new byte[65536]; private int _headerIndex; private int _payloadIndex; private int _pageCounter; private int _logicalStreamId; private long _granulePosition; private byte _lacingTableCount; private const int PAGE_FLAGS_POS = 5; private const int GRANULE_COUNT_POS = 6; private const int CHECKSUM_HEADER_POS = 22; private const int SEGMENT_COUNT_POS = 26; private bool _finalized; public OpusRawWriteStream(Stream outputStream, OpusTags fileTags, int inputSampleRate, int inputNumChannels, bool leaveOpen = false) { _inputSampleRate = inputSampleRate; _logicalStreamId = new Random().Next(); _inputChannels = inputNumChannels; _leaveOpen = leaveOpen; _outputStream = outputStream; _granulePosition = 0L; _crc = new Crc(); BeginNewPage(); WriteOpusHeadPage(); WriteOpusTagsPage(fileTags); } public void WriteSinglePacket(byte[] opusPacket, int offset, int packetSize) { if (_finalized) { throw new InvalidOperationException("Cannot write new samples to Ogg file, the output stream is already closed!"); } if (opusPacket.Length - offset < packetSize) { throw new ArgumentOutOfRangeException("The given audio buffer claims to have " + packetSize + " samples, but it actually only has " + (opusPacket.Length - offset)); } Array.Copy(opusPacket, offset, _currentPayload, _payloadIndex, packetSize); _payloadIndex += packetSize; int numSamplesPerFrame = OpusPacketInfo.GetNumSamplesPerFrame((ReadOnlySpan<byte>)opusPacket.AsSpan(offset), 48000); _granulePosition += numSamplesPerFrame; int num = packetSize; while (num >= 255) { num -= 255; _currentHeader[_headerIndex++] = byte.MaxValue; _lacingTableCount++; } _currentHeader[_headerIndex++] = (byte)num; _lacingTableCount++; if (_lacingTableCount > 248) { FinalizePage(); } } public void Finish() { FinalizePage(); WriteStreamFinishedPage(); _outputStream.Flush(); if (!_leaveOpen) { _outputStream.Dispose(); } _finalized = true; } private void WriteStreamFinishedPage() { _currentHeader[_headerIndex++] = 0; _lacingTableCount++; _currentHeader[5] = 4; FinalizePage(); } private void WriteOpusHeadPage() { if (_payloadIndex != 0) { throw new InvalidOperationException("Must begin writing OpusHead on a new page!"); } _payloadIndex += WriteValueToByteBuffer("OpusHead", _currentPayload, _payloadIndex); _currentPayload[_payloadIndex++] = 1; _currentPayload[_payloadIndex++] = (byte)_inputChannels; short val = 0; _payloadIndex += WriteValueToByteBuffer(val, _currentPayload, _payloadIndex); _payloadIndex += WriteValueToByteBuffer(_inputSampleRate, _currentPayload, _payloadIndex); short val2 = 0; _payloadIndex += WriteValueToByteBuffer(val2, _currentPayload, _payloadIndex); _currentPayload[_payloadIndex++] = 0; _currentHeader[_headerIndex++] = (byte)_payloadIndex; _lacingTableCount++; _currentHeader[5] = 2; FinalizePage(); } private void WriteOpusTagsPage(OpusTags tags = null) { if (tags == null) { tags = new OpusTags(); } if (string.IsNullOrEmpty(tags.Comment)) { tags.Comment = "Concentus.OggFile"; } if (_payloadIndex != 0) { throw new InvalidOperationException("Must begin writing OpusTags on a new page!"); } _payloadIndex += WriteValueToByteBuffer("OpusTags", _currentPayload, _payloadIndex); int num = WriteValueToByteBuffer(tags.Comment, _currentPayload, _payloadIndex + 4); _payloadIndex += WriteValueToByteBuffer(num, _currentPayload, _payloadIndex); _payloadIndex += num; int payloadIndex = _payloadIndex; _payloadIndex += 4; int num2 = 0; foreach (KeyValuePair<string, string> field in tags.Fields) { if (!string.IsNullOrEmpty(field.Key) && !string.IsNullOrEmpty(field.Value)) { num = WriteValueToByteBuffer(field.Key + "=" + field.Value, _currentPayload, _payloadIndex + 4); _payloadIndex += WriteValueToByteBuffer(num, _currentPayload, _payloadIndex); _payloadIndex += num; num2++; } } WriteValueToByteBuffer(num2, _currentPayload, payloadIndex); int num3; for (num3 = _payloadIndex; num3 >= 255; num3 -= 255) { _currentHeader[_headerIndex++] = byte.MaxValue; _lacingTableCount++; } _currentHeader[_headerIndex++] = (byte)num3; _lacingTableCount++; FinalizePage(); } private void BeginNewPage() { _headerIndex = 0; _payloadIndex = 0; _lacingTableCount = 0; _headerIndex += WriteValueToByteBuffer("OggS", _currentHeader, _headerIndex); _currentHeader[_headerIndex++] = 0; _currentHeader[_headerIndex++] = 0; _headerIndex += WriteValueToByteBuffer(_granulePosition, _currentHeader, _headerIndex); _headerIndex += WriteValueToByteBuffer(_logicalStreamId, _currentHeader, _headerIndex); _headerIndex += WriteValueToByteBuffer(_pageCounter, _currentHeader, _headerIndex); _currentHeader[_headerIndex++] = 0; _currentHeader[_headerIndex++] = 0; _currentHeader[_headerIndex++] = 0; _currentHeader[_headerIndex++] = 0; _currentHeader[_headerIndex++] = _lacingTableCount; _pageCounter++; } private void FinalizePage() { if (_finalized) { throw new InvalidOperationException("Cannot finalize page, the output stream is already closed!"); } if (_lacingTableCount != 0) { _currentHeader[26] = _lacingTableCount; WriteValueToByteBuffer(_granulePosition, _currentHeader, 6); _crc.Reset(); for (int i = 0; i < _headerIndex; i++) { _crc.Update(_currentHeader[i]); } for (int j = 0; j < _payloadIndex; j++) { _crc.Update(_currentPayload[j]); } WriteValueToByteBuffer(_crc.Value, _currentHeader, 22); _outputStream.Write(_currentHeader, 0, _headerIndex); _outputStream.Write(_currentPayload, 0, _payloadIndex); BeginNewPage(); } } private static int WriteValueToByteBuffer(int val, byte[] target, int targetOffset) { Array.Copy(BitConverter.GetBytes(val), 0, target, targetOffset, 4); return 4; } private static int WriteValueToByteBuffer(long val, byte[] target, int targetOffset) { Array.Copy(BitConverter.GetBytes(val), 0, target, targetOffset, 8); return 8; } private static int WriteValueToByteBuffer(uint val, byte[] target, int targetOffset) { Array.Copy(BitConverter.GetBytes(val), 0, target, targetOffset, 4); return 4; } private static int WriteValueToByteBuffer(short val, byte[] target, int targetOffset) { Array.Copy(BitConverter.GetBytes(val), 0, target, targetOffset, 2); return 2; } private static int WriteValueToByteBuffer(string val, byte[] target, int targetOffset) { if (string.IsNullOrEmpty(val)) { return 0; } byte[] bytes = Encoding.UTF8.GetBytes(val); Array.Copy(bytes, 0, target, targetOffset, bytes.Length); return bytes.Length; } } public class OpusTagName { public const string Title = "title"; public const string Artist = "artist"; public const string Album = "album"; } public class OpusTags { private string _comment = string.Empty; private IDictionary<string, string> _fields = new Dictionary<string, string>(); public string Comment { get { return _comment; } set { _comment = value; } } public IDictionary<string, string> Fields => _fields; internal static OpusTags ParsePacket(byte[] packet, int packetLength) { if (packetLength < 8) { return null; } if (!"OpusTags".Equals(Encoding.UTF8.GetString(packet, 0, 8))) { return null; } OpusTags opusTags = new OpusTags(); int num = 8; int num2 = BitConverter.ToInt32(packet, num); num += 4; if (num2 > 0) { opusTags._comment = Encoding.UTF8.GetString(packet, num, num2); num += num2; } int num3 = BitConverter.ToInt32(packet, num); num += 4; for (int i = 0; i < num3; i++) { num2 = BitConverter.ToInt32(packet, num); num += 4; if (num2 > 0) { string @string = Encoding.UTF8.GetString(packet, num, num2); num += num2; int num4 = @string.IndexOf('='); if (num4 > 0) { string key = @string.Substring(0, num4); string value = @string.Substring(num4 + 1); opusTags._fields[key] = value; } } } return opusTags; } } internal class ParameterChangeEventArgs : EventArgs { public DataPacket FirstPacket { get; private set; } public ParameterChangeEventArgs(DataPacket firstPacket) { FirstPacket = firstPacket; } } internal class StreamReadBuffer : IDisposable { internal class StreamWrapper { internal Stream Source; internal object LockObject = new object(); internal long EofOffset = long.MaxValue; internal int RefCount = 1; } private class SavedBuffer { public byte[] Buffer; public long BaseOffset; public int End; public int DiscardCount; public long VersionSaved; } private static Dictionary<Stream, StreamWrapper> _lockObjects = new Dictionary<Stream, StreamWrapper>(); private StreamWrapper _wrapper; private int _maxSize; private byte[] _data; private long _baseOffset; private int _end; private int _discardCount; private bool _minimalRead; private long _versionCounter; private List<SavedBuffer> _savedBuffers; public bool MinimalRead { get { return _minimalRead; } set { _minimalRead = value; } } public int MaxSize { get { return _maxSize; } set { if (value < 1) { throw new ArgumentOutOfRangeException("Must be greater than zero."); } int num = 1 << (int)Math.Ceiling(Math.Log(value, 2.0)); if (num < _end) { if (num < _end - _discardCount) { throw new ArgumentOutOfRangeException("Must be greater than or equal to the number of bytes currently buffered."); } CommitDiscard(); byte[] array = new byte[num]; Buffer.BlockCopy(_data, 0, array, 0, _end); _data = array; } _maxSize = num; } } public long BaseOffset => _baseOffset + _discardCount; public int BytesFilled => _end - _discardCount; public int Length => _data.Length; internal long BufferEndOffset { get { if (_end - _discardCount > 0) { return _baseOffset + _discardCount + _maxSize; } if (_wrapper.Source.CanSeek) { return _wrapper.Source.Length; } return _baseOffset + Length; } } internal StreamReadBuffer(Stream source, int initialSize, int maxSize, bool minimalRead) { StreamWrapper value; lock (_lockObjects) { if (!_lockObjects.TryGetValue(source, out value)) { _lockObjects.Add(source, new StreamWrapper { Source = source }); value = _lockObjects[source]; if (source.CanSeek) { value.EofOffset = source.Length; } } else { value.RefCount++; } } initialSize = 2 << (int)Math.Log(initialSize - 1, 2.0); maxSize = 1 << (int)Math.Log(maxSize, 2.0); _wrapper = value; _data = new byte[initialSize]; _maxSize = maxSize; _minimalRead = minimalRead; _savedBuffers = new List<SavedBuffer>(); } public void Dispose() { lock (_lockObjects) { if (--_wrapper.RefCount == 0) { _lockObjects.Remove(_wrapper.Source); } } } public int Read(long offset, byte[] buffer, int index, int count) { if (offset < 0) { throw new ArgumentOutOfRangeException("offset"); } if (buffer == null) { throw new ArgumentNullException("buffer"); } if (index < 0 || index + count > buffer.Length) { throw new ArgumentOutOfRangeException("index"); } if (count < 0) { throw new ArgumentOutOfRangeException("count"); } if (offset >= _wrapper.EofOffset) { return 0; } int srcOffset = EnsureAvailable(offset, ref count, isRecursion: false); Buffer.BlockCopy(_data, srcOffset, buffer, index, count); return count; } internal int ReadByte(long offset) { if (offset < 0) { throw new ArgumentOutOfRangeException("offset"); } if (offset >= _wrapper.EofOffset) { return -1; } int count = 1; int num = EnsureAvailable(offset, ref count, isRecursion: false); if (count == 1) { return _data[num]; } return -1; } private int EnsureAvailable(long offset, ref int count, bool isRecursion) { if (offset >= _baseOffset && offset + count < _baseOffset + _end) { return (int)(offset - _baseOffset); } if (count > _maxSize) { throw new InvalidOperationException("Not enough room in the buffer! Increase the maximum size and try again."); } _versionCounter++; if (!isRecursion) { for (int i = 0; i < _savedBuffers.Count; i++) { long num = _savedBuffers[i].BaseOffset - offset; if ((num < 0 && _savedBuffers[i].End + num > 0) || (num > 0 && count - num > 0)) { SwapBuffers(_savedBuffers[i]); return EnsureAvailable(offset, ref count, isRecursion: true); } } } while (_savedBuffers.Count > 0 && _savedBuffers[0].VersionSaved + 25 < _versionCounter) { _savedBuffers[0].Buffer = null; _savedBuffers.RemoveAt(0); } if (offset < _baseOffset && !_wrapper.Source.CanSeek) { throw new InvalidOperationException("Cannot seek before buffer on forward-only streams!"); } CalcBuffer(offset, count, out var readStart, out var readEnd); count = FillBuffer(offset, count, readStart, readEnd); return (int)(offset - _baseOffset); } private void SaveBuffer() { _savedBuffers.Add(new SavedBuffer { Buffer = _data, BaseOffset = _baseOffset, End = _end, DiscardCount = _discardCount, VersionSaved = _versionCounter }); _data = null; _end = 0; _discardCount = 0; } private void CreateNewBuffer(long offset, int count) { SaveBuffer(); _data = new byte[Math.Min(2 << (int)Math.Log(count - 1, 2.0), _maxSize)]; _baseOffset = offset; } private void SwapBuffers(SavedBuffer savedBuffer) { _savedBuffers.Remove(savedBuffer); SaveBuffer(); _data = savedBuffer.Buffer; _baseOffset = savedBuffer.BaseOffset; _end = savedBuffer.End; _discardCount = savedBuffer.DiscardCount; } private void CalcBuffer(long offset, int count, out int readStart, out int readEnd) { readStart = 0; readEnd = 0; if (offset < _baseOffset) { if (offset + _maxSize <= _baseOffset) { if (_baseOffset - (offset + _maxSize) > _maxSize) { CreateNewBuffer(offset, count); } else { EnsureBufferSize(count, copyContents: false, 0); } _baseOffset = offset; readEnd = count; } else { readEnd = (int)(offset - _baseOffset); EnsureBufferSize(Math.Min((int)(offset + _maxSize - _baseOffset), _end) - readEnd, copyContents: true, readEnd); readEnd = (int)(offset - _baseOffset) - readEnd; } } else if (offset >= _baseOffset + _maxSize) { if (offset - (_baseOffset + _maxSize) > _maxSize) { CreateNewBuffer(offset, count); } else { EnsureBufferSize(count, copyContents: false, 0); } _baseOffset = offset; readEnd = count; } else { readEnd = (int)(offset + count - _baseOffset); int num = Math.Max(readEnd - _maxSize, 0); EnsureBufferSize(readEnd - num, copyContents: true, num); readStart = _end; readEnd = (int)(offset + count - _baseOffset); } } private void EnsureBufferSize(int reqSize, bool copyContents, int copyOffset) { byte[] array = _data; if (reqSize > _data.Length) { if (reqSize > _maxSize) { if (!_wrapper.Source.CanSeek && reqSize - _discardCount > _maxSize) { throw new InvalidOperationException("Not enough room in the buffer! Increase the maximum size and try again."); } int num = reqSize - _maxSize; copyOffset += num; reqSize = _maxSize; } else { int num2; for (num2 = _data.Length; num2 < reqSize; num2 *= 2) { } reqSize = num2; } if (reqSize > _data.Length) { array = new byte[reqSize]; } } if (copyContents) { if ((copyOffset > 0 && copyOffset < _end) || (copyOffset == 0 && array != _data)) { Buffer.BlockCopy(_data, copyOffset, array, 0, _end - copyOffset); if ((_discardCount -= copyOffset) < 0) { _discardCount = 0; } } else if (copyOffset < 0 && -copyOffset < _end) { if (array != _data || _end <= -copyOffset) { Buffer.BlockCopy(_data, 0, array, -copyOffset, Math.Max(_end, Math.Min(_end, _data.Length + copyOffset))); } else { _end = copyOffset; } _discardCount = 0; } else { _end = copyOffset; _discardCount = 0; } _baseOffset += copyOffset; _end -= copyOffset; if (_end > array.Length) { _end = array.Length; } } else { _discardCount = 0; _end = 0; } _data = array; } private int FillBuffer(long offset, int count, int readStart, int readEnd) { long readOffset = _baseOffset + readStart; int readCount = readEnd - readStart; lock (_wrapper.LockObject) { readCount = PrepareStreamForRead(readCount, readOffset); ReadStream(readStart, readCount, readOffset); if (_end < readStart + readCount) { count = Math.Max(0, (int)(_baseOffset + _end - offset)); } else if (!_minimalRead && _end < _data.Length) { readCount = _data.Length - _end; readCount = PrepareStreamForRead(readCount, _baseOffset + _end); _end += _wrapper.Source.Read(_data, _end, readCount); } } return count; } private int PrepareStreamForRead(int readCount, long readOffset) { if (readCount > 0 && _wrapper.Source.Position != readOffset) { if (readOffset < _wrapper.EofOffset) { if (_wrapper.Source.CanSeek) { _wrapper.Source.Position = readOffset; } else { long num = readOffset - _wrapper.Source.Position; if (num < 0) { readCount = 0; } else { while (--num >= 0) { if (_wrapper.Source.ReadByte() == -1) { _wrapper.EofOffset = _wrapper.Source.Position; readCount = 0; break; } } } } } else { readCount = 0; } } return readCount; } private void ReadStream(int readStart, int readCount, long readOffset) { while (readCount > 0 && readOffset < _wrapper.EofOffset) { int num = _wrapper.Source.Read(_data, readStart, readCount); if (num == 0) { break; } readStart += num; readOffset += num; readCount -= num; } if (readStart > _end) { _end = readStart; } } public void DiscardThrough(long offset) { int val = (int)(offset - _baseOffset); _discardCount = Math.Max(val, _discardCount); if (_discardCount >= _data.Length) { CommitDiscard(); } } private void CommitDiscard() { if (_discardCount >= _data.Length || _discardCount >= _end) { _baseOffset += _discardCount; _end = 0; } else { Buffer.BlockCopy(_data, _discardCount, _data, 0, _end - _discardCount); _baseOffset += _discardCount; _end -= _discardCount; } _discardCount = 0; } }
plugins/NVorbis.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using NVorbis.Contracts; using NVorbis.Contracts.Ogg; using NVorbis.Ogg; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")] [assembly: AssemblyCompany("Andrew Ward")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © Andrew Ward 2021")] [assembly: AssemblyDescription("A fully managed implementation of a Xiph.org Foundation Ogg Vorbis decoder.")] [assembly: AssemblyFileVersion("0.10.5.0")] [assembly: AssemblyInformationalVersion("0.10.5")] [assembly: AssemblyProduct("NVorbis")] [assembly: AssemblyTitle("NVorbis")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/NVorbis/NVorbis")] [assembly: NeutralResourcesLanguage("en")] [assembly: AssemblyVersion("0.10.5.0")] namespace NVorbis { internal class Codebook : ICodebook { private class FastRange : IReadOnlyList<int>, IEnumerable<int>, IEnumerable, IReadOnlyCollection<int> { [ThreadStatic] private static FastRange _cachedRange; private int _start; private int _count; public int this[int index] { get { if (index > _count) { throw new ArgumentOutOfRangeException(); } return _start + index; } } public int Count => _count; internal static FastRange Get(int start, int count) { FastRange obj = _cachedRange ?? (_cachedRange = new FastRange()); obj._start = start; obj._count = count; return obj; } private FastRange() { } public IEnumerator<int> GetEnumerator() { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } private int[] _lengths; private float[] _lookupTable; private IReadOnlyList<HuffmanListNode> _overflowList; private IReadOnlyList<HuffmanListNode> _prefixList; private int _prefixBitLength; private int _maxBits; public float this[int entry, int dim] => _lookupTable[entry * Dimensions + dim]; public int Dimensions { get; private set; } public int Entries { get; private set; } public int MapType { get; private set; } public void Init(IPacket packet, IHuffman huffman) { if (packet.ReadBits(24) != 5653314) { throw new InvalidDataException("Book header had invalid signature!"); } Dimensions = (int)packet.ReadBits(16); Entries = (int)packet.ReadBits(24); _lengths = new int[Entries]; InitTree(packet, huffman); InitLookupTable(packet); } private void InitTree(IPacket packet, IHuffman huffman) { int num = 0; bool flag; int num5; if (packet.ReadBit()) { int num2 = (int)packet.ReadBits(5) + 1; int num3 = 0; while (num3 < Entries) { int num4 = (int)packet.ReadBits(Utils.ilog(Entries - num3)); while (--num4 >= 0) { _lengths[num3++] = num2; } num2++; } num = 0; flag = false; num5 = num2; } else { num5 = -1; flag = packet.ReadBit(); for (int i = 0; i < Entries; i++) { if (!flag || packet.ReadBit()) { _lengths[i] = (int)packet.ReadBits(5) + 1; num++; } else { _lengths[i] = -1; } if (_lengths[i] > num5) { num5 = _lengths[i]; } } } if ((_maxBits = num5) > -1) { int[] array = null; if (flag && num >= Entries >> 2) { array = new int[Entries]; Array.Copy(_lengths, array, Entries); flag = false; } int num6 = (flag ? num : 0); int[] array2 = null; int[] array3 = null; if (!flag) { array3 = new int[Entries]; } else if (num6 != 0) { array = new int[num6]; array3 = new int[num6]; array2 = new int[num6]; } if (!ComputeCodewords(flag, array3, array, _lengths, Entries, array2)) { throw new InvalidDataException(); } IReadOnlyList<int> readOnlyList = array2; IReadOnlyList<int> value = readOnlyList ?? FastRange.Get(0, array3.Length); huffman.GenerateTable(value, array ?? _lengths, array3); _prefixList = huffman.PrefixTree; _prefixBitLength = huffman.TableBits; _overflowList = huffman.OverflowList; } } private bool ComputeCodewords(bool sparse, int[] codewords, int[] codewordLengths, int[] len, int n, int[] values) { int num = 0; uint[] array = new uint[32]; int i; for (i = 0; i < n && len[i] <= 0; i++) { } if (i == n) { return true; } AddEntry(sparse, codewords, codewordLengths, 0u, i, num++, len[i], values); for (int j = 1; j <= len[i]; j++) { array[j] = (uint)(1 << 32 - j); } for (int j = i + 1; j < n; j++) { int num2 = len[j]; if (num2 <= 0) { continue; } while (num2 > 0 && array[num2] == 0) { num2--; } if (num2 == 0) { return false; } uint num3 = array[num2]; array[num2] = 0u; AddEntry(sparse, codewords, codewordLengths, Utils.BitReverse(num3), j, num++, len[j], values); if (num2 != len[j]) { for (int num4 = len[j]; num4 > num2; num4--) { array[num4] = num3 + (uint)(1 << 32 - num4); } } } return true; } private void AddEntry(bool sparse, int[] codewords, int[] codewordLengths, uint huffCode, int symbol, int count, int len, int[] values) { if (sparse) { codewords[count] = (int)huffCode; codewordLengths[count] = len; values[count] = symbol; } else { codewords[symbol] = (int)huffCode; } } private void InitLookupTable(IPacket packet) { MapType = (int)packet.ReadBits(4); if (MapType == 0) { return; } float num = Utils.ConvertFromVorbisFloat32((uint)packet.ReadBits(32)); float num2 = Utils.ConvertFromVorbisFloat32((uint)packet.ReadBits(32)); int count = (int)packet.ReadBits(4) + 1; bool flag = packet.ReadBit(); int num3 = Entries * Dimensions; float[] array = new float[num3]; if (MapType == 1) { num3 = lookup1_values(); } uint[] array2 = new uint[num3]; for (int i = 0; i < num3; i++) { array2[i] = (uint)packet.ReadBits(count); } if (MapType == 1) { for (int j = 0; j < Entries; j++) { double num4 = 0.0; int num5 = 1; for (int k = 0; k < Dimensions; k++) { int num6 = j / num5 % num3; double num7 = (double)((float)array2[num6] * num2 + num) + num4; array[j * Dimensions + k] = (float)num7; if (flag) { num4 = num7; } num5 *= num3; } } } else { for (int l = 0; l < Entries; l++) { double num8 = 0.0; int num9 = l * Dimensions; for (int m = 0; m < Dimensions; m++) { double num10 = (double)((float)array2[num9] * num2 + num) + num8; array[l * Dimensions + m] = (float)num10; if (flag) { num8 = num10; } num9++; } } } _lookupTable = array; } private int lookup1_values() { int num = (int)Math.Floor(Math.Exp(Math.Log(Entries) / (double)Dimensions)); if (Math.Floor(Math.Pow(num + 1, Dimensions)) <= (double)Entries) { num++; } return num; } public int DecodeScalar(IPacket packet) { int index = (int)packet.TryPeekBits(_prefixBitLength, out var bitsRead); if (bitsRead == 0) { return -1; } HuffmanListNode huffmanListNode = _prefixList[index]; if (huffmanListNode != null) { packet.SkipBits(huffmanListNode.Length); return huffmanListNode.Value; } index = (int)packet.TryPeekBits(_maxBits, out var _); for (int i = 0; i < _overflowList.Count; i++) { huffmanListNode = _overflowList[i]; if (huffmanListNode.Bits == (index & huffmanListNode.Mask)) { packet.SkipBits(huffmanListNode.Length); return huffmanListNode.Value; } } return -1; } } public abstract class DataPacket : IPacket { [Flags] protected enum PacketFlags : byte { IsResync = 1, IsEndOfStream = 2, IsShort = 4, User0 = 8, User1 = 0x10, User2 = 0x20, User3 = 0x40, User4 = 0x80 } private ulong _bitBucket; private int _bitCount; private byte _overflowBits; private PacketFlags _packetFlags; private int _readBits; public int ContainerOverheadBits { get; set; } public long? GranulePosition { get; set; } public bool IsResync { get { return GetFlag(PacketFlags.IsResync); } set { SetFlag(PacketFlags.IsResync, value); } } public bool IsShort { get { return GetFlag(PacketFlags.IsShort); } private set { SetFlag(PacketFlags.IsShort, value); } } public bool IsEndOfStream { get { return GetFlag(PacketFlags.IsEndOfStream); } set { SetFlag(PacketFlags.IsEndOfStream, value); } } public int BitsRead => _readBits; public int BitsRemaining => TotalBits - _readBits; protected abstract int TotalBits { get; } private bool GetFlag(PacketFlags flag) { return _packetFlags.HasFlag(flag); } private void SetFlag(PacketFlags flag, bool value) { if (value) { _packetFlags |= flag; } else { _packetFlags &= (PacketFlags)(byte)(~(int)flag); } } protected abstract int ReadNextByte(); public virtual void Done() { } public virtual void Reset() { _bitBucket = 0uL; _bitCount = 0; _overflowBits = 0; _readBits = 0; } ulong IPacket.ReadBits(int count) { if (count == 0) { return 0uL; } int bitsRead; ulong result = TryPeekBits(count, out bitsRead); SkipBits(count); return result; } public ulong TryPeekBits(int count, out int bitsRead) { switch (count) { default: throw new ArgumentOutOfRangeException("count"); case 0: bitsRead = 0; return 0uL; case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63: case 64: break; } while (_bitCount < count) { int num = ReadNextByte(); if (num == -1) { bitsRead = _bitCount; return _bitBucket; } _bitBucket = (ulong)((long)(num & 0xFF) << _bitCount) | _bitBucket; _bitCount += 8; if (_bitCount > 64) { _overflowBits = (byte)(num >> 72 - _bitCount); } } ulong num2 = _bitBucket; if (count < 64) { num2 &= (ulong)((1L << count) - 1); } bitsRead = count; return num2; } public void SkipBits(int count) { if (count <= 0) { return; } if (_bitCount > count) { if (count > 63) { _bitBucket = 0uL; } else { _bitBucket >>= count; } if (_bitCount > 64) { int num = _bitCount - 64; _bitBucket |= (ulong)_overflowBits << _bitCount - count - num; if (num > count) { _overflowBits = (byte)(_overflowBits >> count); } } _bitCount -= count; _readBits += count; return; } if (_bitCount == count) { _bitBucket = 0uL; _bitCount = 0; _readBits += count; return; } count -= _bitCount; _readBits += _bitCount; _bitCount = 0; _bitBucket = 0uL; while (count > 8) { if (ReadNextByte() == -1) { count = 0; IsShort = true; break; } count -= 8; _readBits += 8; } if (count > 0) { int num2 = ReadNextByte(); if (num2 == -1) { IsShort = true; return; } _bitBucket = (ulong)(num2 >> count); _bitCount = 8 - count; _readBits += count; } } } public static class Extensions { public static int Read(this IPacket packet, byte[] buffer, int index, int count) { if (index < 0 || index >= buffer.Length) { throw new ArgumentOutOfRangeException("index"); } if (count < 0 || index + count > buffer.Length) { throw new ArgumentOutOfRangeException("count"); } for (int i = 0; i < count; i++) { int bitsRead; byte b = (byte)packet.TryPeekBits(8, out bitsRead); if (bitsRead == 0) { return i; } buffer[index++] = b; packet.SkipBits(8); } return count; } public static byte[] ReadBytes(this IPacket packet, int count) { byte[] array = new byte[count]; int num = packet.Read(array, 0, count); if (num < count) { byte[] array2 = new byte[num]; Buffer.BlockCopy(array, 0, array2, 0, num); return array2; } return array; } public static bool ReadBit(this IPacket packet) { return packet.ReadBits(1) == 1; } public static byte PeekByte(this IPacket packet) { int bitsRead; return (byte)packet.TryPeekBits(8, out bitsRead); } public static byte ReadByte(this IPacket packet) { return (byte)packet.ReadBits(8); } public static short ReadInt16(this IPacket packet) { return (short)packet.ReadBits(16); } public static int ReadInt32(this IPacket packet) { return (int)packet.ReadBits(32); } public static long ReadInt64(this IPacket packet) { return (long)packet.ReadBits(64); } public static ushort ReadUInt16(this IPacket packet) { return (ushort)packet.ReadBits(16); } public static uint ReadUInt32(this IPacket packet) { return (uint)packet.ReadBits(32); } public static ulong ReadUInt64(this IPacket packet) { return packet.ReadBits(64); } public static void SkipBytes(this IPacket packet, int count) { packet.SkipBits(count * 8); } } internal class Factory : IFactory { public IHuffman CreateHuffman() { return new Huffman(); } public IMdct CreateMdct() { return new Mdct(); } public ICodebook CreateCodebook() { return new Codebook(); } public IFloor CreateFloor(IPacket packet) { return (int)packet.ReadBits(16) switch { 0 => new Floor0(), 1 => new Floor1(), _ => throw new InvalidDataException("Invalid floor type!"), }; } public IMapping CreateMapping(IPacket packet) { if (packet.ReadBits(16) != 0L) { throw new InvalidDataException("Invalid mapping type!"); } return new Mapping(); } public IMode CreateMode() { return new Mode(); } public IResidue CreateResidue(IPacket packet) { return (int)packet.ReadBits(16) switch { 0 => new Residue0(), 1 => new Residue1(), 2 => new Residue2(), _ => throw new InvalidDataException("Invalid residue type!"), }; } } internal class Floor0 : IFloor { private class Data : IFloorData { internal float[] Coeff; internal float Amp; public bool ExecuteChannel { get { if (ForceEnergy || Amp > 0f) { return !ForceNoEnergy; } return false; } } public bool ForceEnergy { get; set; } public bool ForceNoEnergy { get; set; } } private int _order; private int _rate; private int _bark_map_size; private int _ampBits; private int _ampOfs; private int _ampDiv; private ICodebook[] _books; private int _bookBits; private Dictionary<int, float[]> _wMap; private Dictionary<int, int[]> _barkMaps; public void Init(IPacket packet, int channels, int block0Size, int block1Size, ICodebook[] codebooks) { _order = (int)packet.ReadBits(8); _rate = (int)packet.ReadBits(16); _bark_map_size = (int)packet.ReadBits(16); _ampBits = (int)packet.ReadBits(6); _ampOfs = (int)packet.ReadBits(8); _books = new ICodebook[(int)packet.ReadBits(4) + 1]; if (_order < 1 || _rate < 1 || _bark_map_size < 1 || _books.Length == 0) { throw new InvalidDataException(); } _ampDiv = (1 << _ampBits) - 1; for (int i = 0; i < _books.Length; i++) { int num = (int)packet.ReadBits(8); if (num < 0 || num >= codebooks.Length) { throw new InvalidDataException(); } ICodebook codebook = codebooks[num]; if (codebook.MapType == 0 || codebook.Dimensions < 1) { throw new InvalidDataException(); } _books[i] = codebook; } _bookBits = Utils.ilog(_books.Length); _barkMaps = new Dictionary<int, int[]> { [block0Size] = SynthesizeBarkCurve(block0Size / 2), [block1Size] = SynthesizeBarkCurve(block1Size / 2) }; _wMap = new Dictionary<int, float[]> { [block0Size] = SynthesizeWDelMap(block0Size / 2), [block1Size] = SynthesizeWDelMap(block1Size / 2) }; } private int[] SynthesizeBarkCurve(int n) { float num = (float)_bark_map_size / toBARK(_rate / 2); int[] array = new int[n + 1]; for (int i = 0; i < n - 1; i++) { array[i] = Math.Min(_bark_map_size - 1, (int)Math.Floor(toBARK((float)_rate / 2f / (float)n * (float)i) * num)); } array[n] = -1; return array; } private static float toBARK(double lsp) { return (float)(13.1 * Math.Atan(0.00074 * lsp) + 2.24 * Math.Atan(1.85E-08 * lsp * lsp) + 0.0001 * lsp); } private float[] SynthesizeWDelMap(int n) { float num = (float)(Math.PI / (double)_bark_map_size); float[] array = new float[n]; for (int i = 0; i < n; i++) { array[i] = 2f * (float)Math.Cos(num * (float)i); } return array; } public IFloorData Unpack(IPacket packet, int blockSize, int channel) { Data data = new Data { Coeff = new float[_order + 1] }; data.Amp = packet.ReadBits(_ampBits); if (data.Amp > 0f) { Array.Clear(data.Coeff, 0, data.Coeff.Length); data.Amp = data.Amp / (float)_ampDiv * (float)_ampOfs; uint num = (uint)packet.ReadBits(_bookBits); if (num >= _books.Length) { data.Amp = 0f; return data; } ICodebook codebook = _books[num]; int i = 0; while (i < _order) { int num2 = codebook.DecodeScalar(packet); if (num2 == -1) { data.Amp = 0f; return data; } int num3 = 0; for (; i < _order; i++) { if (num3 >= codebook.Dimensions) { break; } data.Coeff[i] = codebook[num2, num3]; num3++; } } float num4 = 0f; int num5 = 0; while (num5 < _order) { int num6 = 0; while (num5 < _order && num6 < codebook.Dimensions) { data.Coeff[num5] += num4; num5++; num6++; } num4 = data.Coeff[num5 - 1]; } } return data; } public void Apply(IFloorData floorData, int blockSize, float[] residue) { if (!(floorData is Data data)) { throw new ArgumentException("Incorrect packet data!"); } int num = blockSize / 2; if (data.Amp > 0f) { int[] array = _barkMaps[blockSize]; float[] array2 = _wMap[blockSize]; int num2 = 0; for (num2 = 0; num2 < _order; num2++) { data.Coeff[num2] = 2f * (float)Math.Cos(data.Coeff[num2]); } num2 = 0; while (num2 < num) { int num3 = array[num2]; float num4 = 0.5f; float num5 = 0.5f; float num6 = array2[num3]; int i; for (i = 1; i < _order; i += 2) { num5 *= num6 - data.Coeff[i - 1]; num4 *= num6 - data.Coeff[i]; } if (i == _order) { num5 *= num6 - data.Coeff[i - 1]; num4 *= num4 * (4f - num6 * num6); num5 *= num5; } else { num4 *= num4 * (2f - num6); num5 *= num5 * (2f + num6); } num5 = data.Amp / (float)Math.Sqrt(num4 + num5) - (float)_ampOfs; num5 = (float)Math.Exp(num5 * 0.11512925f); residue[num2] *= num5; while (array[++num2] == num3) { residue[num2] *= num5; } } } else { Array.Clear(residue, 0, num); } } } internal class Floor1 : IFloor { private class Data : IFloorData { internal int[] Posts = new int[64]; internal int PostCount; public bool ExecuteChannel { get { if (ForceEnergy || PostCount > 0) { return !ForceNoEnergy; } return false; } } public bool ForceEnergy { get; set; } public bool ForceNoEnergy { get; set; } } private int[] _partitionClass; private int[] _classDimensions; private int[] _classSubclasses; private int[] _xList; private int[] _classMasterBookIndex; private int[] _hNeigh; private int[] _lNeigh; private int[] _sortIdx; private int _multiplier; private int _range; private int _yBits; private ICodebook[] _classMasterbooks; private ICodebook[][] _subclassBooks; private int[][] _subclassBookIndex; private static readonly int[] _rangeLookup = new int[4] { 256, 128, 86, 64 }; private static readonly int[] _yBitsLookup = new int[4] { 8, 7, 7, 6 }; private static readonly float[] inverse_dB_table = new float[256] { 1.0649863E-07f, 1.1341951E-07f, 1.2079015E-07f, 1.2863978E-07f, 1.369995E-07f, 1.459025E-07f, 1.5538409E-07f, 1.6548181E-07f, 1.7623574E-07f, 1.8768856E-07f, 1.998856E-07f, 2.128753E-07f, 2.2670913E-07f, 2.4144197E-07f, 2.5713223E-07f, 2.7384212E-07f, 2.9163792E-07f, 3.1059022E-07f, 3.307741E-07f, 3.5226967E-07f, 3.7516213E-07f, 3.995423E-07f, 4.255068E-07f, 4.5315863E-07f, 4.8260745E-07f, 5.1397E-07f, 5.4737063E-07f, 5.829419E-07f, 6.208247E-07f, 6.611694E-07f, 7.041359E-07f, 7.4989464E-07f, 7.98627E-07f, 8.505263E-07f, 9.057983E-07f, 9.646621E-07f, 1.0273513E-06f, 1.0941144E-06f, 1.1652161E-06f, 1.2409384E-06f, 1.3215816E-06f, 1.4074654E-06f, 1.4989305E-06f, 1.5963394E-06f, 1.7000785E-06f, 1.8105592E-06f, 1.9282195E-06f, 2.053526E-06f, 2.1869757E-06f, 2.3290977E-06f, 2.4804558E-06f, 2.6416496E-06f, 2.813319E-06f, 2.9961443E-06f, 3.1908505E-06f, 3.39821E-06f, 3.619045E-06f, 3.8542307E-06f, 4.1047006E-06f, 4.371447E-06f, 4.6555283E-06f, 4.958071E-06f, 5.280274E-06f, 5.623416E-06f, 5.988857E-06f, 6.3780467E-06f, 6.7925284E-06f, 7.2339453E-06f, 7.704048E-06f, 8.2047E-06f, 8.737888E-06f, 9.305725E-06f, 9.910464E-06f, 1.0554501E-05f, 1.1240392E-05f, 1.1970856E-05f, 1.2748789E-05f, 1.3577278E-05f, 1.4459606E-05f, 1.5399271E-05f, 1.6400005E-05f, 1.7465769E-05f, 1.8600793E-05f, 1.9809577E-05f, 2.1096914E-05f, 2.2467912E-05f, 2.3928002E-05f, 2.5482977E-05f, 2.7139005E-05f, 2.890265E-05f, 3.078091E-05f, 3.2781227E-05f, 3.4911533E-05f, 3.718028E-05f, 3.9596467E-05f, 4.2169668E-05f, 4.491009E-05f, 4.7828602E-05f, 5.0936775E-05f, 5.424693E-05f, 5.7772202E-05f, 6.152657E-05f, 6.552491E-05f, 6.9783084E-05f, 7.4317984E-05f, 7.914758E-05f, 8.429104E-05f, 8.976875E-05f, 9.560242E-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f, 0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f, 0.00015820454f, 0.00016848555f, 0.00017943469f, 0.00019109536f, 0.00020351382f, 0.0002167393f, 0.00023082423f, 0.00024582449f, 0.00026179955f, 0.00027881275f, 0.00029693157f, 0.00031622787f, 0.00033677815f, 0.00035866388f, 0.00038197188f, 0.00040679457f, 0.00043323037f, 0.0004613841f, 0.0004913675f, 0.00052329927f, 0.0005573062f, 0.0005935231f, 0.0006320936f, 0.0006731706f, 0.000716917f, 0.0007635063f, 0.00081312325f, 0.00086596457f, 0.00092223985f, 0.0009821722f, 0.0010459992f, 0.0011139743f, 0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f, 0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f, 0.0019632196f, 0.0020908006f, 0.0022266726f, 0.0023713743f, 0.0025254795f, 0.0026895993f, 0.0028643848f, 0.0030505287f, 0.003248769f, 0.0034598925f, 0.0036847359f, 0.0039241905f, 0.0041792067f, 0.004450795f, 0.004740033f, 0.005048067f, 0.0053761187f, 0.005725489f, 0.0060975635f, 0.0064938175f, 0.0069158226f, 0.0073652514f, 0.007843887f, 0.008353627f, 0.008896492f, 0.009474637f, 0.010090352f, 0.01074608f, 0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f, 0.014722068f, 0.015678791f, 0.016697686f, 0.017782796f, 0.018938422f, 0.020169148f, 0.021479854f, 0.022875736f, 0.02436233f, 0.025945531f, 0.027631618f, 0.029427277f, 0.031339627f, 0.03337625f, 0.035545226f, 0.037855156f, 0.0403152f, 0.042935107f, 0.045725275f, 0.048696756f, 0.05186135f, 0.05523159f, 0.05882085f, 0.062643364f, 0.06671428f, 0.07104975f, 0.075666964f, 0.08058423f, 0.08582105f, 0.09139818f, 0.097337745f, 0.1036633f, 0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f, 0.14201812f, 0.15124726f, 0.16107617f, 0.1715438f, 0.18269168f, 0.19456401f, 0.20720787f, 0.22067343f, 0.23501402f, 0.25028655f, 0.26655158f, 0.28387362f, 0.3023213f, 0.32196787f, 0.34289113f, 0.36517414f, 0.3889052f, 0.41417846f, 0.44109413f, 0.4697589f, 0.50028646f, 0.53279793f, 0.5674221f, 0.6042964f, 0.64356697f, 0.6853896f, 0.72993004f, 0.777365f, 0.8278826f, 0.88168305f, 0.9389798f, 1f }; public void Init(IPacket packet, int channels, int block0Size, int block1Size, ICodebook[] codebooks) { int num = -1; _partitionClass = new int[(uint)packet.ReadBits(5)]; for (int i = 0; i < _partitionClass.Length; i++) { _partitionClass[i] = (int)packet.ReadBits(4); if (_partitionClass[i] > num) { num = _partitionClass[i]; } } _classDimensions = new int[++num]; _classSubclasses = new int[num]; _classMasterbooks = new ICodebook[num]; _classMasterBookIndex = new int[num]; _subclassBooks = new ICodebook[num][]; _subclassBookIndex = new int[num][]; for (int j = 0; j < num; j++) { _classDimensions[j] = (int)packet.ReadBits(3) + 1; _classSubclasses[j] = (int)packet.ReadBits(2); if (_classSubclasses[j] > 0) { _classMasterBookIndex[j] = (int)packet.ReadBits(8); _classMasterbooks[j] = codebooks[_classMasterBookIndex[j]]; } _subclassBooks[j] = new ICodebook[1 << _classSubclasses[j]]; _subclassBookIndex[j] = new int[_subclassBooks[j].Length]; for (int k = 0; k < _subclassBooks[j].Length; k++) { int num2 = (int)packet.ReadBits(8) - 1; if (num2 >= 0) { _subclassBooks[j][k] = codebooks[num2]; } _subclassBookIndex[j][k] = num2; } } _multiplier = (int)packet.ReadBits(2); _range = _rangeLookup[_multiplier]; _yBits = _yBitsLookup[_multiplier]; _multiplier++; int num3 = (int)packet.ReadBits(4); List<int> list = new List<int>(); list.Add(0); list.Add(1 << num3); for (int l = 0; l < _partitionClass.Length; l++) { int num4 = _partitionClass[l]; for (int m = 0; m < _classDimensions[num4]; m++) { list.Add((int)packet.ReadBits(num3)); } } _xList = list.ToArray(); _lNeigh = new int[list.Count]; _hNeigh = new int[list.Count]; _sortIdx = new int[list.Count]; _sortIdx[0] = 0; _sortIdx[1] = 1; for (int n = 2; n < _lNeigh.Length; n++) { _lNeigh[n] = 0; _hNeigh[n] = 1; _sortIdx[n] = n; for (int num5 = 2; num5 < n; num5++) { int num6 = _xList[num5]; if (num6 < _xList[n]) { if (num6 > _xList[_lNeigh[n]]) { _lNeigh[n] = num5; } } else if (num6 < _xList[_hNeigh[n]]) { _hNeigh[n] = num5; } } } for (int num7 = 0; num7 < _sortIdx.Length - 1; num7++) { for (int num8 = num7 + 1; num8 < _sortIdx.Length; num8++) { if (_xList[num7] == _xList[num8]) { throw new InvalidDataException(); } if (_xList[_sortIdx[num7]] > _xList[_sortIdx[num8]]) { int num9 = _sortIdx[num7]; _sortIdx[num7] = _sortIdx[num8]; _sortIdx[num8] = num9; } } } } public IFloorData Unpack(IPacket packet, int blockSize, int channel) { Data data = new Data(); if (packet.ReadBit()) { int num = 2; data.Posts[0] = (int)packet.ReadBits(_yBits); data.Posts[1] = (int)packet.ReadBits(_yBits); for (int i = 0; i < _partitionClass.Length; i++) { int num2 = _partitionClass[i]; int num3 = _classDimensions[num2]; int num4 = _classSubclasses[num2]; int num5 = (1 << num4) - 1; uint num6 = 0u; if (num4 > 0 && (num6 = (uint)_classMasterbooks[num2].DecodeScalar(packet)) == uint.MaxValue) { num = 0; break; } for (int j = 0; j < num3; j++) { ICodebook codebook = _subclassBooks[num2][num6 & num5]; num6 >>= num4; if (codebook != null && (data.Posts[num] = codebook.DecodeScalar(packet)) == -1) { num = 0; i = _partitionClass.Length; break; } num++; } } data.PostCount = num; } return data; } public void Apply(IFloorData floorData, int blockSize, float[] residue) { if (!(floorData is Data data)) { throw new ArgumentException("Incorrect packet data!", "packetData"); } int num = blockSize / 2; if (data.PostCount > 0) { bool[] array = UnwrapPosts(data); int num2 = 0; int num3 = data.Posts[0] * _multiplier; for (int i = 1; i < data.PostCount; i++) { int num4 = _sortIdx[i]; if (array[num4]) { int num5 = _xList[num4]; int num6 = data.Posts[num4] * _multiplier; if (num2 < num) { RenderLineMulti(num2, num3, Math.Min(num5, num), num6, residue); } num2 = num5; num3 = num6; } if (num2 >= num) { break; } } if (num2 < num) { RenderLineMulti(num2, num3, num, num3, residue); } } else { Array.Clear(residue, 0, num); } } private bool[] UnwrapPosts(Data data) { bool[] array = new bool[64]; array[0] = true; array[1] = true; int[] array2 = new int[64]; array2[0] = data.Posts[0]; array2[1] = data.Posts[1]; for (int i = 2; i < data.PostCount; i++) { int num = _lNeigh[i]; int num2 = _hNeigh[i]; int num3 = RenderPoint(_xList[num], array2[num], _xList[num2], array2[num2], _xList[i]); int num4 = data.Posts[i]; int num5 = _range - num3; int num6 = num3; int num7 = ((num5 >= num6) ? (num6 * 2) : (num5 * 2)); if (num4 != 0) { array[num] = true; array[num2] = true; array[i] = true; if (num4 >= num7) { if (num5 > num6) { array2[i] = num4 - num6 + num3; } else { array2[i] = num3 - num4 + num5 - 1; } } else if (num4 % 2 == 1) { array2[i] = num3 - (num4 + 1) / 2; } else { array2[i] = num3 + num4 / 2; } } else { array[i] = false; array2[i] = num3; } } for (int j = 0; j < data.PostCount; j++) { data.Posts[j] = array2[j]; } return array; } private int RenderPoint(int x0, int y0, int x1, int y1, int X) { int num = y1 - y0; int num2 = x1 - x0; int num3 = Math.Abs(num) * (X - x0) / num2; if (num < 0) { return y0 - num3; } return y0 + num3; } private void RenderLineMulti(int x0, int y0, int x1, int y1, float[] v) { int num = y1 - y0; int num2 = x1 - x0; int num3 = Math.Abs(num); int num4 = 1 - ((num >> 31) & 1) * 2; int num5 = num / num2; int num6 = x0; int num7 = y0; int num8 = -num2; v[x0] *= inverse_dB_table[y0]; num3 -= Math.Abs(num5) * num2; while (++num6 < x1) { num7 += num5; num8 += num3; if (num8 >= 0) { num8 -= num2; num7 += num4; } v[num6] *= inverse_dB_table[num7]; } } } internal class Huffman : IHuffman, IComparer<HuffmanListNode> { private const int MAX_TABLE_BITS = 10; public int TableBits { get; private set; } public IReadOnlyList<HuffmanListNode> PrefixTree { get; private set; } public IReadOnlyList<HuffmanListNode> OverflowList { get; private set; } public void GenerateTable(IReadOnlyList<int> values, int[] lengthList, int[] codeList) { HuffmanListNode[] array = new HuffmanListNode[lengthList.Length]; int num = 0; for (int i = 0; i < array.Length; i++) { array[i] = new HuffmanListNode { Value = values[i], Length = ((lengthList[i] <= 0) ? 99999 : lengthList[i]), Bits = codeList[i], Mask = (1 << lengthList[i]) - 1 }; if (lengthList[i] > 0 && num < lengthList[i]) { num = lengthList[i]; } } Array.Sort(array, 0, array.Length, this); int num2 = ((num > 10) ? 10 : num); List<HuffmanListNode> list = new List<HuffmanListNode>(1 << num2); List<HuffmanListNode> list2 = null; for (int j = 0; j < array.Length && array[j].Length < 99999; j++) { int length = array[j].Length; if (length > num2) { list2 = new List<HuffmanListNode>(array.Length - j); for (; j < array.Length && array[j].Length < 99999; j++) { list2.Add(array[j]); } continue; } int num3 = 1 << num2 - length; HuffmanListNode huffmanListNode = array[j]; for (int k = 0; k < num3; k++) { int num4 = (k << length) | huffmanListNode.Bits; while (list.Count <= num4) { list.Add(null); } list[num4] = huffmanListNode; } } while (list.Count < 1 << num2) { list.Add(null); } TableBits = num2; PrefixTree = list; OverflowList = list2; } int IComparer<HuffmanListNode>.Compare(HuffmanListNode x, HuffmanListNode y) { int num = x.Length - y.Length; if (num == 0) { return x.Bits - y.Bits; } return num; } } [Obsolete("Moved to NVorbis.Contracts.IContainerReader", true)] public interface IContainerReader : NVorbis.Contracts.IContainerReader, IDisposable { [Obsolete("Use Streams.Select(s => s.StreamSerial).ToArray() instead.", true)] int[] StreamSerials { get; } [Obsolete("No longer supported.", true)] int PagesRead { get; } [Obsolete("Moved to NewStreamCallback.", true)] event EventHandler<NewStreamEventArgs> NewStream; [Obsolete("Renamed to TryInit().", true)] bool Init(); [Obsolete("No longer supported.", true)] int GetTotalPageCount(); } [Obsolete("Moved to NVorbis.Contracts.IPacketProvider", true)] public interface IPacketProvider : NVorbis.Contracts.IPacketProvider { [Obsolete("Moved to per-stream IStreamStats instance on IStreamDecoder.Stats or VorbisReader.Stats.", true)] long ContainerBits { get; } [Obsolete("No longer supported.", true)] event EventHandler ParameterChange; [Obsolete("No longer supported.", true)] int GetTotalPageCount(); [Obsolete("Getting a packet by index is no longer supported.", true)] DataPacket GetPacket(int packetIndex); [Obsolete("Moved to long SeekTo(long, int, GetPacketGranuleCount)", true)] DataPacket FindPacket(long granulePos, Func<DataPacket, DataPacket, int> packetGranuleCountCallback); [Obsolete("Seeking to a specified packet is no longer supported. See SeekTo(...) instead.", true)] void SeekToPacket(DataPacket packet, int preRoll); } [Obsolete("Moved to NVorbis.Contracts.IStreamStats", true)] public interface IVorbisStreamStatus : IStreamStats { [Obsolete("No longer supported.", true)] TimeSpan PageLatency { get; } [Obsolete("No longer supported.", true)] TimeSpan PacketLatency { get; } [Obsolete("No longer supported.", true)] TimeSpan SecondLatency { get; } [Obsolete("No longer supported.", true)] int PagesRead { get; } [Obsolete("No longer supported.", true)] int TotalPages { get; } [Obsolete("Use IStreamDecoder.HasClipped instead. VorbisReader.HasClipped will return the same value for the stream it is handling.", true)] bool Clipped { get; } } internal class Mapping : IMapping { private IMdct _mdct; private int[] _couplingAngle; private int[] _couplingMangitude; private IFloor[] _submapFloor; private IResidue[] _submapResidue; private IFloor[] _channelFloor; private IResidue[] _channelResidue; public void Init(IPacket packet, int channels, IFloor[] floors, IResidue[] residues, IMdct mdct) { int num = 1; if (packet.ReadBit()) { num += (int)packet.ReadBits(4); } int num2 = 0; if (packet.ReadBit()) { num2 = (int)packet.ReadBits(8) + 1; } int count = Utils.ilog(channels - 1); _couplingAngle = new int[num2]; _couplingMangitude = new int[num2]; for (int i = 0; i < num2; i++) { int num3 = (int)packet.ReadBits(count); int num4 = (int)packet.ReadBits(count); if (num3 == num4 || num3 > channels - 1 || num4 > channels - 1) { throw new InvalidDataException("Invalid magnitude or angle in mapping header!"); } _couplingAngle[i] = num4; _couplingMangitude[i] = num3; } if (packet.ReadBits(2) != 0L) { throw new InvalidDataException("Reserved bits not 0 in mapping header."); } int[] array = new int[channels]; if (num > 1) { for (int j = 0; j < channels; j++) { array[j] = (int)packet.ReadBits(4); if (array[j] > num) { throw new InvalidDataException("Invalid channel mux submap index in mapping header!"); } } } _submapFloor = new IFloor[num]; _submapResidue = new IResidue[num]; for (int k = 0; k < num; k++) { packet.SkipBits(8); int num5 = (int)packet.ReadBits(8); if (num5 >= floors.Length) { throw new InvalidDataException("Invalid floor number in mapping header!"); } int num6 = (int)packet.ReadBits(8); if (num6 >= residues.Length) { throw new InvalidDataException("Invalid residue number in mapping header!"); } _submapFloor[k] = floors[num5]; _submapResidue[k] = residues[num6]; } _channelFloor = new IFloor[channels]; _channelResidue = new IResidue[channels]; for (int l = 0; l < channels; l++) { _channelFloor[l] = _submapFloor[array[l]]; _channelResidue[l] = _submapResidue[array[l]]; } _mdct = mdct; } public void DecodePacket(IPacket packet, int blockSize, int channels, float[][] buffer) { int num = blockSize >> 1; IFloorData[] array = new IFloorData[_channelFloor.Length]; bool[] array2 = new bool[_channelFloor.Length]; for (int i = 0; i < _channelFloor.Length; i++) { array[i] = _channelFloor[i].Unpack(packet, blockSize, i); array2[i] = !array[i].ExecuteChannel; Array.Clear(buffer[i], 0, num); } for (int j = 0; j < _couplingAngle.Length; j++) { if (array[_couplingAngle[j]].ExecuteChannel || array[_couplingMangitude[j]].ExecuteChannel) { array[_couplingAngle[j]].ForceEnergy = true; array[_couplingMangitude[j]].ForceEnergy = true; } } for (int k = 0; k < _submapFloor.Length; k++) { for (int l = 0; l < _channelFloor.Length; l++) { if (_submapFloor[k] != _channelFloor[l] || _submapResidue[k] != _channelResidue[l]) { array[l].ForceNoEnergy = true; } } _submapResidue[k].Decode(packet, array2, blockSize, buffer); } for (int num2 = _couplingAngle.Length - 1; num2 >= 0; num2--) { if (array[_couplingAngle[num2]].ExecuteChannel || array[_couplingMangitude[num2]].ExecuteChannel) { float[] array3 = buffer[_couplingMangitude[num2]]; float[] array4 = buffer[_couplingAngle[num2]]; for (int m = 0; m < num; m++) { float num3 = array3[m]; float num4 = array4[m]; float num5; float num6; if (num3 > 0f) { if (num4 > 0f) { num5 = num3; num6 = num3 - num4; } else { num6 = num3; num5 = num3 + num4; } } else if (num4 > 0f) { num5 = num3; num6 = num3 + num4; } else { num6 = num3; num5 = num3 - num4; } array3[m] = num5; array4[m] = num6; } } } for (int n = 0; n < _channelFloor.Length; n++) { if (array[n].ExecuteChannel) { _channelFloor[n].Apply(array[n], blockSize, buffer[n]); _mdct.Reverse(buffer[n], blockSize); } else { Array.Clear(buffer[n], num, num); } } } } internal class Mdct : IMdct { private class MdctImpl { private readonly int _n; private readonly int _n2; private readonly int _n4; private readonly int _n8; private readonly int _ld; private readonly float[] _a; private readonly float[] _b; private readonly float[] _c; private readonly ushort[] _bitrev; public MdctImpl(int n) { _n = n; _n2 = n >> 1; _n4 = _n2 >> 1; _n8 = _n4 >> 1; _ld = Utils.ilog(n) - 1; _a = new float[_n2]; _b = new float[_n2]; _c = new float[_n4]; int num; int num2 = (num = 0); while (num2 < _n4) { _a[num] = (float)Math.Cos((float)(4 * num2) * MathF.PI / (float)n); _a[num + 1] = (float)(0.0 - Math.Sin((float)(4 * num2) * MathF.PI / (float)n)); _b[num] = (float)Math.Cos((float)(num + 1) * MathF.PI / (float)n / 2f) * 0.5f; _b[num + 1] = (float)Math.Sin((float)(num + 1) * MathF.PI / (float)n / 2f) * 0.5f; num2++; num += 2; } num2 = (num = 0); while (num2 < _n8) { _c[num] = (float)Math.Cos((float)(2 * (num + 1)) * MathF.PI / (float)n); _c[num + 1] = (float)(0.0 - Math.Sin((float)(2 * (num + 1)) * MathF.PI / (float)n)); num2++; num += 2; } _bitrev = new ushort[_n8]; for (int i = 0; i < _n8; i++) { _bitrev[i] = (ushort)(Utils.BitReverse((uint)i, _ld - 3) << 2); } } internal void CalcReverse(float[] buffer) { float[] array = new float[_n2]; int num = _n2 - 2; int num2 = 0; int i = 0; for (int n = _n2; i != n; i += 4) { array[num + 1] = buffer[i] * _a[num2] - buffer[i + 2] * _a[num2 + 1]; array[num] = buffer[i] * _a[num2 + 1] + buffer[i + 2] * _a[num2]; num -= 2; num2 += 2; } i = _n2 - 3; while (num >= 0) { array[num + 1] = (0f - buffer[i + 2]) * _a[num2] - (0f - buffer[i]) * _a[num2 + 1]; array[num] = (0f - buffer[i + 2]) * _a[num2 + 1] + (0f - buffer[i]) * _a[num2]; num -= 2; num2 += 2; i -= 4; } float[] array2 = array; int num3 = _n2 - 8; int num4 = _n4; int num5 = 0; int num6 = _n4; int num7 = 0; while (num3 >= 0) { float num8 = array2[num4 + 1] - array2[num5 + 1]; float num9 = array2[num4] - array2[num5]; buffer[num6 + 1] = array2[num4 + 1] + array2[num5 + 1]; buffer[num6] = array2[num4] + array2[num5]; buffer[num7 + 1] = num8 * _a[num3 + 4] - num9 * _a[num3 + 5]; buffer[num7] = num9 * _a[num3 + 4] + num8 * _a[num3 + 5]; num8 = array2[num4 + 3] - array2[num5 + 3]; num9 = array2[num4 + 2] - array2[num5 + 2]; buffer[num6 + 3] = array2[num4 + 3] + array2[num5 + 3]; buffer[num6 + 2] = array2[num4 + 2] + array2[num5 + 2]; buffer[num7 + 3] = num8 * _a[num3] - num9 * _a[num3 + 1]; buffer[num7 + 2] = num9 * _a[num3] + num8 * _a[num3 + 1]; num3 -= 8; num6 += 4; num7 += 4; num4 += 4; num5 += 4; } int n2 = _n >> 4; int num10 = _n2 - 1; _ = _n4; step3_iter0_loop(n2, buffer, num10 - 0, -_n8); step3_iter0_loop(_n >> 4, buffer, _n2 - 1 - _n4, -_n8); int lim = _n >> 5; int num11 = _n2 - 1; _ = _n8; step3_inner_r_loop(lim, buffer, num11 - 0, -(_n >> 4), 16); step3_inner_r_loop(_n >> 5, buffer, _n2 - 1 - _n8, -(_n >> 4), 16); step3_inner_r_loop(_n >> 5, buffer, _n2 - 1 - _n8 * 2, -(_n >> 4), 16); step3_inner_r_loop(_n >> 5, buffer, _n2 - 1 - _n8 * 3, -(_n >> 4), 16); int j; for (j = 2; j < _ld - 3 >> 1; j++) { int num12 = _n >> j + 2; int num13 = num12 >> 1; int num14 = 1 << j + 1; for (int k = 0; k < num14; k++) { step3_inner_r_loop(_n >> j + 4, buffer, _n2 - 1 - num12 * k, -num13, 1 << j + 3); } } for (; j < _ld - 6; j++) { int num15 = _n >> j + 2; int num16 = 1 << j + 3; int num17 = num15 >> 1; int num18 = _n >> j + 6; int n3 = 1 << j + 1; int num19 = _n2 - 1; int num20 = 0; for (int num21 = num18; num21 > 0; num21--) { step3_inner_s_loop(n3, buffer, num19, -num17, num20, num16, num15); num20 += num16 * 4; num19 -= 8; } } step3_inner_s_loop_ld654(_n >> 5, buffer, _n2 - 1, _n); int num22 = 0; int num23 = _n4 - 4; int num24 = _n2 - 4; while (num23 >= 0) { int num25 = _bitrev[num22]; array2[num24 + 3] = buffer[num25]; array2[num24 + 2] = buffer[num25 + 1]; array2[num23 + 3] = buffer[num25 + 2]; array2[num23 + 2] = buffer[num25 + 3]; num25 = _bitrev[num22 + 1]; array2[num24 + 1] = buffer[num25]; array2[num24] = buffer[num25 + 1]; array2[num23 + 1] = buffer[num25 + 2]; array2[num23] = buffer[num25 + 3]; num23 -= 4; num24 -= 4; num22 += 2; } int num26 = 0; int num27 = 0; int num28 = _n2 - 4; while (num27 < num28) { float num29 = array2[num27] - array2[num28 + 2]; float num30 = array2[num27 + 1] + array2[num28 + 3]; float num31 = _c[num26 + 1] * num29 + _c[num26] * num30; float num32 = _c[num26 + 1] * num30 - _c[num26] * num29; float num33 = array2[num27] + array2[num28 + 2]; float num34 = array2[num27 + 1] - array2[num28 + 3]; array2[num27] = num33 + num31; array2[num27 + 1] = num34 + num32; array2[num28 + 2] = num33 - num31; array2[num28 + 3] = num32 - num34; num29 = array2[num27 + 2] - array2[num28]; num30 = array2[num27 + 3] + array2[num28 + 1]; num31 = _c[num26 + 3] * num29 + _c[num26 + 2] * num30; num32 = _c[num26 + 3] * num30 - _c[num26 + 2] * num29; num33 = array2[num27 + 2] + array2[num28]; num34 = array2[num27 + 3] - array2[num28 + 1]; array2[num27 + 2] = num33 + num31; array2[num27 + 3] = num34 + num32; array2[num28] = num33 - num31; array2[num28 + 1] = num32 - num34; num26 += 4; num27 += 4; num28 -= 4; } int num35 = _n2 - 8; int num36 = _n2 - 8; int num37 = 0; int num38 = _n2 - 4; int num39 = _n2; int num40 = _n - 4; while (num36 >= 0) { float num41 = array[num36 + 6] * _b[num35 + 7] - array[num36 + 7] * _b[num35 + 6]; float num42 = (0f - array[num36 + 6]) * _b[num35 + 6] - array[num36 + 7] * _b[num35 + 7]; buffer[num37] = num41; buffer[num38 + 3] = 0f - num41; buffer[num39] = num42; buffer[num40 + 3] = num42; float num43 = array[num36 + 4] * _b[num35 + 5] - array[num36 + 5] * _b[num35 + 4]; float num44 = (0f - array[num36 + 4]) * _b[num35 + 4] - array[num36 + 5] * _b[num35 + 5]; buffer[num37 + 1] = num43; buffer[num38 + 2] = 0f - num43; buffer[num39 + 1] = num44; buffer[num40 + 2] = num44; num41 = array[num36 + 2] * _b[num35 + 3] - array[num36 + 3] * _b[num35 + 2]; num42 = (0f - array[num36 + 2]) * _b[num35 + 2] - array[num36 + 3] * _b[num35 + 3]; buffer[num37 + 2] = num41; buffer[num38 + 1] = 0f - num41; buffer[num39 + 2] = num42; buffer[num40 + 1] = num42; num43 = array[num36] * _b[num35 + 1] - array[num36 + 1] * _b[num35]; num44 = (0f - array[num36]) * _b[num35] - array[num36 + 1] * _b[num35 + 1]; buffer[num37 + 3] = num43; buffer[num38] = 0f - num43; buffer[num39 + 3] = num44; buffer[num40] = num44; num35 -= 8; num36 -= 8; num37 += 4; num39 += 4; num38 -= 4; num40 -= 4; } } private void step3_iter0_loop(int n, float[] e, int i_off, int k_off) { int num = i_off; int num2 = num + k_off; int num3 = 0; for (int num4 = n >> 2; num4 > 0; num4--) { float num5 = e[num] - e[num2]; float num6 = e[num - 1] - e[num2 - 1]; e[num] += e[num2]; e[num - 1] += e[num2 - 1]; e[num2] = num5 * _a[num3] - num6 * _a[num3 + 1]; e[num2 - 1] = num6 * _a[num3] + num5 * _a[num3 + 1]; num3 += 8; num5 = e[num - 2] - e[num2 - 2]; num6 = e[num - 3] - e[num2 - 3]; e[num - 2] += e[num2 - 2]; e[num - 3] += e[num2 - 3]; e[num2 - 2] = num5 * _a[num3] - num6 * _a[num3 + 1]; e[num2 - 3] = num6 * _a[num3] + num5 * _a[num3 + 1]; num3 += 8; num5 = e[num - 4] - e[num2 - 4]; num6 = e[num - 5] - e[num2 - 5]; e[num - 4] += e[num2 - 4]; e[num - 5] += e[num2 - 5]; e[num2 - 4] = num5 * _a[num3] - num6 * _a[num3 + 1]; e[num2 - 5] = num6 * _a[num3] + num5 * _a[num3 + 1]; num3 += 8; num5 = e[num - 6] - e[num2 - 6]; num6 = e[num - 7] - e[num2 - 7]; e[num - 6] += e[num2 - 6]; e[num - 7] += e[num2 - 7]; e[num2 - 6] = num5 * _a[num3] - num6 * _a[num3 + 1]; e[num2 - 7] = num6 * _a[num3] + num5 * _a[num3 + 1]; num3 += 8; num -= 8; num2 -= 8; } } private void step3_inner_r_loop(int lim, float[] e, int d0, int k_off, int k1) { int num = d0; int num2 = num + k_off; int num3 = 0; for (int num4 = lim >> 2; num4 > 0; num4--) { float num5 = e[num] - e[num2]; float num6 = e[num - 1] - e[num2 - 1]; e[num] += e[num2]; e[num - 1] += e[num2 - 1]; e[num2] = num5 * _a[num3] - num6 * _a[num3 + 1]; e[num2 - 1] = num6 * _a[num3] + num5 * _a[num3 + 1]; num3 += k1; num5 = e[num - 2] - e[num2 - 2]; num6 = e[num - 3] - e[num2 - 3]; e[num - 2] += e[num2 - 2]; e[num - 3] += e[num2 - 3]; e[num2 - 2] = num5 * _a[num3] - num6 * _a[num3 + 1]; e[num2 - 3] = num6 * _a[num3] + num5 * _a[num3 + 1]; num3 += k1; num5 = e[num - 4] - e[num2 - 4]; num6 = e[num - 5] - e[num2 - 5]; e[num - 4] += e[num2 - 4]; e[num - 5] += e[num2 - 5]; e[num2 - 4] = num5 * _a[num3] - num6 * _a[num3 + 1]; e[num2 - 5] = num6 * _a[num3] + num5 * _a[num3 + 1]; num3 += k1; num5 = e[num - 6] - e[num2 - 6]; num6 = e[num - 7] - e[num2 - 7]; e[num - 6] += e[num2 - 6]; e[num - 7] += e[num2 - 7]; e[num2 - 6] = num5 * _a[num3] - num6 * _a[num3 + 1]; e[num2 - 7] = num6 * _a[num3] + num5 * _a[num3 + 1]; num3 += k1; num -= 8; num2 -= 8; } } private void step3_inner_s_loop(int n, float[] e, int i_off, int k_off, int a, int a_off, int k0) { float num = _a[a]; float num2 = _a[a + 1]; float num3 = _a[a + a_off]; float num4 = _a[a + a_off + 1]; float num5 = _a[a + a_off * 2]; float num6 = _a[a + a_off * 2 + 1]; float num7 = _a[a + a_off * 3]; float num8 = _a[a + a_off * 3 + 1]; int num9 = i_off; int num10 = num9 + k_off; for (int num11 = n; num11 > 0; num11--) { float num12 = e[num9] - e[num10]; float num13 = e[num9 - 1] - e[num10 - 1]; e[num9] += e[num10]; e[num9 - 1] += e[num10 - 1]; e[num10] = num12 * num - num13 * num2; e[num10 - 1] = num13 * num + num12 * num2; num12 = e[num9 - 2] - e[num10 - 2]; num13 = e[num9 - 3] - e[num10 - 3]; e[num9 - 2] += e[num10 - 2]; e[num9 - 3] += e[num10 - 3]; e[num10 - 2] = num12 * num3 - num13 * num4; e[num10 - 3] = num13 * num3 + num12 * num4; num12 = e[num9 - 4] - e[num10 - 4]; num13 = e[num9 - 5] - e[num10 - 5]; e[num9 - 4] += e[num10 - 4]; e[num9 - 5] += e[num10 - 5]; e[num10 - 4] = num12 * num5 - num13 * num6; e[num10 - 5] = num13 * num5 + num12 * num6; num12 = e[num9 - 6] - e[num10 - 6]; num13 = e[num9 - 7] - e[num10 - 7]; e[num9 - 6] += e[num10 - 6]; e[num9 - 7] += e[num10 - 7]; e[num10 - 6] = num12 * num7 - num13 * num8; e[num10 - 7] = num13 * num7 + num12 * num8; num9 -= k0; num10 -= k0; } } private void step3_inner_s_loop_ld654(int n, float[] e, int i_off, int base_n) { int num = base_n >> 3; float num2 = _a[num]; int num3 = i_off; int num4 = num3 - 16 * n; while (num3 > num4) { float num5 = e[num3] - e[num3 - 8]; float num6 = e[num3 - 1] - e[num3 - 9]; e[num3] += e[num3 - 8]; e[num3 - 1] += e[num3 - 9]; e[num3 - 8] = num5; e[num3 - 9] = num6; num5 = e[num3 - 2] - e[num3 - 10]; num6 = e[num3 - 3] - e[num3 - 11]; e[num3 - 2] += e[num3 - 10]; e[num3 - 3] += e[num3 - 11]; e[num3 - 10] = (num5 + num6) * num2; e[num3 - 11] = (num6 - num5) * num2; num5 = e[num3 - 12] - e[num3 - 4]; num6 = e[num3 - 5] - e[num3 - 13]; e[num3 - 4] += e[num3 - 12]; e[num3 - 5] += e[num3 - 13]; e[num3 - 12] = num6; e[num3 - 13] = num5; num5 = e[num3 - 14] - e[num3 - 6]; num6 = e[num3 - 7] - e[num3 - 15]; e[num3 - 6] += e[num3 - 14]; e[num3 - 7] += e[num3 - 15]; e[num3 - 14] = (num5 + num6) * num2; e[num3 - 15] = (num5 - num6) * num2; iter_54(e, num3); iter_54(e, num3 - 8); num3 -= 16; } } private void iter_54(float[] e, int z) { float num = e[z] - e[z - 4]; float num2 = e[z] + e[z - 4]; float num3 = e[z - 2] + e[z - 6]; float num4 = e[z - 2] - e[z - 6]; e[z] = num2 + num3; e[z - 2] = num2 - num3; float num5 = e[z - 3] - e[z - 7]; e[z - 4] = num + num5; e[z - 6] = num - num5; float num6 = e[z - 1] - e[z - 5]; float num7 = e[z - 1] + e[z - 5]; float num8 = e[z - 3] + e[z - 7]; e[z - 1] = num7 + num8; e[z - 3] = num7 - num8; e[z - 5] = num6 - num4; e[z - 7] = num6 + num4; } } private const float M_PI = MathF.PI; private Dictionary<int, MdctImpl> _setupCache = new Dictionary<int, MdctImpl>(); public void Reverse(float[] samples, int sampleCount) { if (!_setupCache.TryGetValue(sampleCount, out var value)) { value = new MdctImpl(sampleCount); _setupCache[sampleCount] = value; } value.CalcReverse(samples); } } internal class Mode : IMode { private struct OverlapInfo { public int PacketStartIndex; public int PacketTotalLength; public int PacketValidLength; } private const float M_PI2 = MathF.PI / 2f; private int _channels; private bool _blockFlag; private int _blockSize; private IMapping _mapping; private float[][] _windows; private OverlapInfo[] _overlapInfo; public void Init(IPacket packet, int channels, int block0Size, int block1Size, IMapping[] mappings) { _channels = channels; _blockFlag = packet.ReadBit(); if (packet.ReadBits(32) != 0L) { throw new InvalidDataException("Mode header had invalid window or transform type!"); } int num = (int)packet.ReadBits(8); if (num >= mappings.Length) { throw new InvalidDataException("Mode header had invalid mapping index!"); } _mapping = mappings[num]; if (_blockFlag) { _blockSize = block1Size; _windows = new float[4][] { CalcWindow(block0Size, block1Size, block0Size), CalcWindow(block1Size, block1Size, block0Size), CalcWindow(block0Size, block1Size, block1Size), CalcWindow(block1Size, block1Size, block1Size) }; _overlapInfo = new OverlapInfo[4] { CalcOverlap(block0Size, block1Size, block0Size), CalcOverlap(block1Size, block1Size, block0Size), CalcOverlap(block0Size, block1Size, block1Size), CalcOverlap(block1Size, block1Size, block1Size) }; } else { _blockSize = block0Size; _windows = new float[1][] { CalcWindow(block0Size, block0Size, block0Size) }; } } private static float[] CalcWindow(int prevBlockSize, int blockSize, int nextBlockSize) { float[] array = new float[blockSize]; int num = prevBlockSize / 2; int num2 = nextBlockSize / 2; int num3 = blockSize / 4 - num / 2; int num4 = blockSize - blockSize / 4 - num2 / 2; for (int i = 0; i < num; i++) { float num5 = (float)Math.Sin(((double)i + 0.5) / (double)num * 1.5707963705062866); num5 *= num5; array[num3 + i] = (float)Math.Sin(num5 * (MathF.PI / 2f)); } for (int j = num3 + num; j < num4; j++) { array[j] = 1f; } for (int k = 0; k < num2; k++) { float num6 = (float)Math.Sin(((double)(num2 - k) - 0.5) / (double)num2 * 1.5707963705062866); num6 *= num6; array[num4 + k] = (float)Math.Sin(num6 * (MathF.PI / 2f)); } return array; } private static OverlapInfo CalcOverlap(int prevBlockSize, int blockSize, int nextBlockSize) { int num = prevBlockSize / 4; int num2 = nextBlockSize / 4; int packetStartIndex = blockSize / 4 - num; int num3 = blockSize / 4 * 3 + num2; int packetValidLength = num3 - num2 * 2; OverlapInfo result = default(OverlapInfo); result.PacketStartIndex = packetStartIndex; result.PacketValidLength = packetValidLength; result.PacketTotalLength = num3; return result; } private bool GetPacketInfo(IPacket packet, out int windowIndex, out int packetStartIndex, out int packetValidLength, out int packetTotalLength) { if (packet.IsShort) { windowIndex = 0; packetStartIndex = 0; packetValidLength = 0; packetTotalLength = 0; return false; } if (_blockFlag) { bool flag = packet.ReadBit(); bool flag2 = packet.ReadBit(); windowIndex = (flag ? 1 : 0) + (flag2 ? 2 : 0); OverlapInfo overlapInfo = _overlapInfo[windowIndex]; packetStartIndex = overlapInfo.PacketStartIndex; packetValidLength = overlapInfo.PacketValidLength; packetTotalLength = overlapInfo.PacketTotalLength; } else { windowIndex = 0; packetStartIndex = 0; packetValidLength = _blockSize / 2; packetTotalLength = _blockSize; } return true; } public bool Decode(IPacket packet, float[][] buffer, out int packetStartindex, out int packetValidLength, out int packetTotalLength) { if (GetPacketInfo(packet, out var windowIndex, out packetStartindex, out packetValidLength, out packetTotalLength)) { _mapping.DecodePacket(packet, _blockSize, _channels, buffer); float[] array = _windows[windowIndex]; for (int i = 0; i < _blockSize; i++) { for (int j = 0; j < _channels; j++) { buffer[j][i] *= array[i]; } } return true; } return false; } public int GetPacketSampleCount(IPacket packet) { GetPacketInfo(packet, out var _, out var packetStartIndex, out var packetValidLength, out var _); return packetValidLength - packetStartIndex; } } [Serializable] public class NewStreamEventArgs : EventArgs { public IStreamDecoder StreamDecoder { get; } public bool IgnoreStream { get; set; } public NewStreamEventArgs(IStreamDecoder streamDecoder) { StreamDecoder = streamDecoder ?? throw new ArgumentNullException("streamDecoder"); } } internal class Residue0 : IResidue { private int _channels; private int _begin; private int _end; private int _partitionSize; private int _classifications; private int _maxStages; private ICodebook[][] _books; private ICodebook _classBook; private int[] _cascade; private int[][] _decodeMap; private static int icount(int v) { int num = 0; while (v != 0) { num += v & 1; v >>= 1; } return num; } public virtual void Init(IPacket packet, int channels, ICodebook[] codebooks) { _begin = (int)packet.ReadBits(24); _end = (int)packet.ReadBits(24); _partitionSize = (int)packet.ReadBits(24) + 1; _classifications = (int)packet.ReadBits(6) + 1; _classBook = codebooks[(uint)packet.ReadBits(8)]; _cascade = new int[_classifications]; int num = 0; for (int i = 0; i < _classifications; i++) { int num2 = (int)packet.ReadBits(3); if (packet.ReadBit()) { _cascade[i] = ((int)packet.ReadBits(5) << 3) | num2; } else { _cascade[i] = num2; } num += icount(_cascade[i]); } int[] array = new int[num]; for (int j = 0; j < num; j++) { array[j] = (int)packet.ReadBits(8); if (codebooks[array[j]].MapType == 0) { throw new InvalidDataException(); } } int entries = _classBook.Entries; int num3 = _classBook.Dimensions; int num4 = 1; while (num3 > 0) { num4 *= _classifications; if (num4 > entries) { throw new InvalidDataException(); } num3--; } _books = new ICodebook[_classifications][]; num = 0; int num5 = 0; for (int k = 0; k < _classifications; k++) { int num6 = Utils.ilog(_cascade[k]); _books[k] = new ICodebook[num6]; if (num6 <= 0) { continue; } num5 = Math.Max(num5, num6); for (int l = 0; l < num6; l++) { if ((_cascade[k] & (1 << l)) > 0) { _books[k][l] = codebooks[array[num++]]; } } } _maxStages = num5; _decodeMap = new int[num4][]; for (int m = 0; m < num4; m++) { int num7 = m; int num8 = num4 / _classifications; _decodeMap[m] = new int[_classBook.Dimensions]; for (int n = 0; n < _classBook.Dimensions; n++) { int num9 = num7 / num8; num7 -= num9 * num8; num8 /= _classifications; _decodeMap[m][n] = num9; } } _channels = channels; } public virtual void Decode(IPacket packet, bool[] doNotDecodeChannel, int blockSize, float[][] buffer) { int num = ((_end < blockSize / 2) ? _end : (blockSize / 2)) - _begin; if (num <= 0 || Array.IndexOf(doNotDecodeChannel, value: false) == -1) { return; } int num2 = num / _partitionSize; int num3 = (num2 + _classBook.Dimensions - 1) / _classBook.Dimensions; int[,][] array = new int[_channels, num3][]; for (int i = 0; i < _maxStages; i++) { int j = 0; int num4 = 0; while (j < num2) { if (i == 0) { for (int k = 0; k < _channels; k++) { int num5 = _classBook.DecodeScalar(packet); if (num5 >= 0 && num5 < _decodeMap.Length) { array[k, num4] = _decodeMap[num5]; continue; } j = num2; i = _maxStages; break; } } int num6 = 0; for (; j < num2; j++) { if (num6 >= _classBook.Dimensions) { break; } int offset = _begin + j * _partitionSize; for (int l = 0; l < _channels; l++) { int num7 = array[l, num4][num6]; if ((_cascade[num7] & (1 << i)) != 0) { ICodebook codebook = _books[num7][i]; if (codebook != null && WriteVectors(codebook, packet, buffer, l, offset, _partitionSize)) { j = num2; i = _maxStages; break; } } } num6++; } num4++; } } } protected virtual bool WriteVectors(ICodebook codebook, IPacket packet, float[][] residue, int channel, int offset, int partitionSize) { float[] array = residue[channel]; int num = partitionSize / codebook.Dimensions; int[] array2 = new int[num]; for (int i = 0; i < num; i++) { if ((array2[i] = codebook.DecodeScalar(packet)) == -1) { return true; } } for (int j = 0; j < codebook.Dimensions; j++) { int num2 = 0; while (num2 < num) { array[offset] += codebook[array2[num2], j]; num2++; offset++; } } return false; } } internal class Residue1 : Residue0 { protected override bool WriteVectors(ICodebook codebook, IPacket packet, float[][] residue, int channel, int offset, int partitionSize) { float[] array = residue[channel]; int num = 0; while (num < partitionSize) { int num2 = codebook.DecodeScalar(packet); if (num2 == -1) { return true; } for (int i = 0; i < codebook.Dimensions; i++) { array[offset + num] += codebook[num2, i]; num++; } } return false; } } internal class Residue2 : Residue0 { private int _channels; public override void Init(IPacket packet, int channels, ICodebook[] codebooks) { _channels = channels; base.Init(packet, 1, codebooks); } public override void Decode(IPacket packet, bool[] doNotDecodeChannel, int blockSize, float[][] buffer) { base.Decode(packet, doNotDecodeChannel, blockSize * _channels, buffer); } protected override bool WriteVectors(ICodebook codebook, IPacket packet, float[][] residue, int channel, int offset, int partitionSize) { int num = 0; offset /= _channels; int num2 = 0; while (num2 < partitionSize) { int num3 = codebook.DecodeScalar(packet); if (num3 == -1) { return true; } int num4 = 0; while (num4 < codebook.Dimensions) { residue[num][offset] += codebook[num3, num4]; if (++num == _channels) { num = 0; offset++; } num4++; num2++; } } return false; } } public sealed class StreamDecoder : IStreamDecoder, IDisposable { private NVorbis.Contracts.IPacketProvider _packetProvider; private IFactory _factory; private StreamStats _stats; private byte _channels; private int _sampleRate; private int _block0Size; private int _block1Size; private IMode[] _modes; private int _modeFieldBits; private string _vendor; private string[] _comments; private ITagData _tags; private long _currentPosition; private bool _hasClipped; private bool _hasPosition; private bool _eosFound; private float[][] _nextPacketBuf; private float[][] _prevPacketBuf; private int _prevPacketStart; private int _prevPacketEnd; private int _prevPacketStop; private static readonly byte[] PacketSignatureStream = new byte[11] { 1, 118, 111, 114, 98, 105, 115, 0, 0, 0, 0 }; private static readonly byte[] PacketSignatureComments = new byte[7] { 3, 118, 111, 114, 98, 105, 115 }; private static readonly byte[] PacketSignatureBooks = new byte[7] { 5, 118, 111, 114, 98, 105, 115 }; internal static Func<IFactory> CreateFactory { get; set; } = () => new Factory(); public int Channels => _channels; public int SampleRate => _sampleRate; public int UpperBitrate { get; private set; } public int NominalBitrate { get; private set; } public int LowerBitrate { get; private set; } public ITagData Tags => _tags ?? (_tags = new TagData(_vendor, _comments)); public TimeSpan TotalTime => TimeSpan.FromSeconds((double)TotalSamples / (double)_sampleRate); public long TotalSamples => (_packetProvider ?? throw new ObjectDisposedException("StreamDecoder")).GetGranuleCount(); public TimeSpan TimePosition { get { return TimeSpan.FromSeconds((double)_currentPosition / (double)_sampleRate); } set { SeekTo(value); } } public long SamplePosition { get { return _currentPosition; } set { SeekTo(value); } } public bool ClipSamples { get; set; } public bool HasClipped => _hasClipped; public bool IsEndOfStream { get { if (_eosFound) { return _prevPacketBuf == null; } return false; } } public IStreamStats Stats => _stats; public StreamDecoder(NVorbis.Contracts.IPacketProvider packetProvider) : this(packetProvider, new Factory()) { } internal StreamDecoder(NVorbis.Contracts.IPacketProvider packetProvider, IFactory factory) { _packetProvider = packetProvider ?? throw new ArgumentNullException("packetProvider"); _factory = factory ?? throw new ArgumentNullException("factory"); _stats = new StreamStats(); _currentPosition = 0L; ClipSamples = true; IPacket packet = _packetProvider.PeekNextPacket(); if (!ProcessHeaderPackets(packet)) { _packetProvider = null; packet.Reset(); throw GetInvalidStreamException(packet); } } private static Exception GetInvalidStreamException(IPacket packet) { try { ulong num = packet.ReadBits(64); if (num == 7233173838382854223L) { return new ArgumentException("Found OPUS bitstream."); } if ((num & 0xFF) == 127) { return new ArgumentException("Found FLAC bitstream."); } switch (num) { case 2314885909937746003uL: return new ArgumentException("Found Speex bitstream."); case 28254585843050854uL: return new ArgumentException("Found Skeleton metadata bitstream."); default: if ((num & 0xFFFFFFFFFFFF00L) == 27428895509214208L) { return new ArgumentException("Found Theora bitsream."); } return new ArgumentException("Could not find Vorbis data to decode."); } } finally { packet.Reset(); } } private bool ProcessHeaderPackets(IPacket packet) { if (!ProcessHeaderPacket(packet, LoadStreamHeader, delegate { _packetProvider.GetNextPacket().Done(); })) { return false; } if (!ProcessHeaderPacket(_packetProvider.GetNextPacket(), LoadComments, delegate(IPacket pkt) { pkt.Done(); })) { return false; } if (!ProcessHeaderPacket(_packetProvider.GetNextPacket(), LoadBooks, delegate(IPacket pkt) { pkt.Done(); })) { return false; } _currentPosition = 0L; ResetDecoder(); return true; } private static bool ProcessHeaderPacket(IPacket packet, Func<IPacket, bool> processAction, Action<IPacket> doneAction) { if (packet != null) { try { return processAction(packet); } finally { doneAction(packet); } } return false; } private static bool ValidateHeader(IPacket packet, byte[] expected) { for (int i = 0; i < expected.Length; i++) { if (expected[i] != packet.ReadBits(8)) { return false; } } return true; } private static string ReadString(IPacket packet) { int num = (int)packet.ReadBits(32); if (num == 0) { return string.Empty; } byte[] array = new byte[num]; if (packet.Read(array, 0, num) < num) { throw new InvalidDataException("Could not read full string!"); } return Encoding.UTF8.GetString(array); } private bool LoadStreamHeader(IPacket packet) { if (!ValidateHeader(packet, PacketSignatureStream)) { return false; } _channels = (byte)packet.ReadBits(8); _sampleRate = (int)packet.ReadBits(32); UpperBitrate = (int)packet.ReadBits(32); NominalBitrate = (int)packet.ReadBits(32); LowerBitrate = (int)packet.ReadBits(32); _block0Size = 1 << (int)packet.ReadBits(4); _block1Size = 1 << (int)packet.ReadBits(4); if (NominalBitrate == 0 && UpperBitrate > 0 && LowerBitrate > 0) { NominalBitrate = (UpperBitrate + LowerBitrate) / 2; } _stats.SetSampleRate(_sampleRate); _stats.AddPacket(-1, packet.BitsRead, packet.BitsRemaining, packet.ContainerOverheadBits); return true; } private bool LoadComments(IPacket packet) { if (!ValidateHeader(packet, PacketSignatureComments)) { return false; } _vendor = ReadString(packet); _comments = new string[packet.ReadBits(32)]; for (int i = 0; i < _comments.Length; i++) { _comments[i] = ReadString(packet); } _stats.AddPacket(-1, packet.BitsRead, packet.BitsRemaining, packet.ContainerOverheadBits); return true; } private bool LoadBooks(IPacket packet) { if (!ValidateHeader(packet, PacketSignatureBooks)) { return false; } IMdct mdct = _factory.CreateMdct(); IHuffman huffman = _factory.CreateHuffman(); ICodebook[] array = new ICodebook[packet.ReadBits(8) + 1]; for (int i = 0; i < array.Length; i++) { array[i] = _factory.CreateCodebook(); array[i].Init(packet, huffman); } int num = (int)packet.ReadBits(6) + 1; packet.SkipBits(16 * num); IFloor[] array2 = new IFloor[packet.ReadBits(6) + 1]; for (int j = 0; j < array2.Length; j++) { array2[j] = _factory.CreateFloor(packet); array2[j].Init(packet, _channels, _block0Size, _block1Size, array); } IResidue[] array3 = new IResidue[packet.ReadBits(6) + 1]; for (int k = 0; k < array3.Length; k++) { array3[k] = _factory.CreateResidue(packet); array3[k].Init(packet, _channels, array); } IMapping[] array4 = new IMapping[packet.ReadBits(6) + 1]; for (int l = 0; l < array4.Length; l++) { array4[l] = _factory.CreateMapping(packet); array4[l].Init(packet, _channels, array2, array3, mdct); } _modes = new IMode[packet.ReadBits(6) + 1]; for (int m = 0; m < _modes.Length; m++) { _modes[m] = _factory.CreateMode(); _modes[m].Init(packet, _channels, _block0Size, _block1Size, array4); } if (!packet.ReadBit()) { throw new InvalidDataException("Book packet did not end on correct bit!"); } _modeFieldBits = Utils.ilog(_modes.Length - 1); _stats.AddPacket(-1, packet.BitsRead, packet.BitsRemaining, packet.ContainerOverheadBits); return true; } private void ResetDecoder() { _prevPacketBuf = null; _prevPacketStart = 0; _prevPacketEnd = 0; _prevPacketStop = 0; _nextPacketBuf = null; _eosFound = false; _hasClipped = false; _hasPosition = false; } public int Read(Span<float> buffer, int offset, int count) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0 || offset + count > buffer.Length) { throw new ArgumentOutOfRangeException("offset"); } if (count % _channels != 0) { throw new ArgumentOutOfRangeException("count", "Must be a multiple of Channels!"); } if (_packetProvider == null) { throw new ObjectDisposedException("StreamDecoder"); } if (count == 0) { return 0; } int num = offset; int num2 = offset + count; while (num < num2) { if (_prevPacketStart == _prevPacketEnd) { if (_eosFound) { _nextPacketBuf = null; _prevPacketBuf = null; break; } if (!ReadNextPacket((num - offset) / _channels, out var samplePosition)) { _prevPacketEnd = _prevPacketStop; } if (samplePosition.HasValue && !_hasPosition) { _hasPosition = true; _currentPosition = samplePosition.Value - (_prevPacketEnd - _prevPacketStart) - (num - offset) / _channels; } } int num3 = Math.Min((num2 - num) / _channels, _prevPacketEnd - _prevPacketStart); if (num3 > 0) { num = ((!ClipSamples) ? (num + CopyBuffer(buffer, num, num3)) : (num + ClippingCopyBuffer(buffer, num, num3))); } } count = num - offset; _currentPosition += count / _channels; return count; } private int ClippingCopyBuffer(Span<float> target, int targetIndex, int count) { int num = targetIndex; while (count > 0) { for (int i = 0; i < _channels; i++) { target[num++] = Utils.ClipValue(_prevPacketBuf[i][_prevPacketStart], ref _hasClipped); } _prevPacketStart++; count--; } return num - targetIndex; } private int CopyBuffer(Span<float> target, int targetIndex, int count) { int num = targetIndex; while (count > 0) { for (int i = 0; i < _channels; i++) { target[num++] = _prevPacketBuf[i][_prevPacketStart]; } _prevPacketStart++; count--; } return num - targetIndex; } private bool ReadNextPacket(int bufferedSamples, out long? samplePosition) { int packetStartindex; int packetValidLength; int packetTotalLength; bool isEndOfStream; int bitsRead; int bitsRemaining; int containerOverheadBits; float[][] array = DecodeNextPacket(out packetStartindex, out packetValidLength, out packetTotalLength, out isEndOfStream, out samplePosition, out bitsRead, out bitsRemaining, out containerOverheadBits); _eosFound |= isEndOfStream; if (array == null) { _stats.AddPacket(0, bitsRead, bitsRemaining, containerOverheadBits); return false; } if (samplePosition.HasValue && isEndOfStream) { long num = _currentPosition + bufferedSamples + packetValidLength - packetStartindex; int num2 = (int)(samplePosition.Value - num); if (num2 < 0) { packetValidLength += num2; } } if (_prevPacketEnd > 0) { OverlapBuffers(_prevPacketBuf, array, _prevPacketStart, _prevPacketStop, packetStartindex, _channels); _prevPacketStart = packetStartindex; } else if (_prevPacketBuf == null) { _prevPacketStart = packetValidLength; } _stats.AddPacket(packetValidLength - _prevPacketStart, bitsRead, bitsRemaining, containerOverheadBits); _nextPacketBuf = _prevPacketBuf; _prevPacketEnd = packetValidLength; _prevPacketStop = packetTotalLength; _prevPacketBuf = array; return true; } private float[][] DecodeNextPacket(out int packetStartindex, out int packetValidLength, out int packetTotalLength, out bool isEndOfStream, out long? samplePosition, out int bitsRead, out int bitsRemaining, out int containerOverheadBits) { IPacket packet = null; try { if ((packet = _packetProvider.GetNextPacket()) == null) { isEndOfStream = true; } else { isEndOfStream = packet.IsEndOfStream; if (packet.IsResync) { _hasPosition = false; } containerOverheadBits = packet.ContainerOverheadBits; if (packet.ReadBit()) { bitsRemaining = packet.BitsRemaining + 1; } else { IMode mode = _modes[(uint)packet.ReadBits(_modeFieldBits)]; if (_nextPacketBuf == null) { _nextPacketBuf = new float[_channels][]; for (int i = 0; i < _channels; i++) { _nextPacketBuf[i] = new float[_block1Size]; } } if (mode.Decode(packet, _nextPacketBuf, out packetStartindex, out packetValidLength, out packetTotalLength)) { samplePosition = packet.GranulePosition; bitsRead = packet.BitsRead; bitsRemaining = packet.BitsRemaining; return _nextPacketBuf; } bitsRemaining = packet.BitsRead + packet.BitsRemaining; } } packetStartindex = 0; packetValidLength = 0; packetTotalLength = 0; samplePosition = null; bitsRead = 0; bitsRemaining = 0; containerOverheadBits = 0; return null; } finally { packet?.Done(); } } private static void OverlapBuffers(float[][] previous, float[][] next, int prevStart, int prevLen, int nextStart, int channels) { while (prevStart < prevLen) { for (int i = 0; i < channels; i++) { next[i][nextStart] += previous[i][prevStart]; } prevStart++; nextStart++; } } public void SeekTo(TimeSpan timePosition, SeekOrigin seekOrigin = SeekOrigin.Begin) { SeekTo((long)((double)SampleRate * timePosition.TotalSeconds), seekOrigin); } public void SeekTo(long samplePosition, SeekOrigin seekOrigin = SeekOrigin.Begin) { if (_packetProvider == null) { throw new ObjectDisposedException("StreamDecoder"); } if (!_packetProvider.CanSeek) { throw new InvalidOperationException("Seek is not supported by the Contracts.IPacketProvider instance."); } switch (seekOrigin) { case SeekOrigin.Current: samplePosition = SamplePosition - samplePosition; break; case SeekOrigin.End: samplePosition = TotalSamples - samplePosition; break; default: throw new ArgumentOutOfRangeException("seekOrigin"); case SeekOrigin.Begin: break; } if (samplePosition < 0) { throw new ArgumentOutOfRangeException("samplePosition"); } int num; if (samplePosition == 0L) { _packetProvider.SeekTo(0L, 0, GetPacketGranules); num = 0; } else { long num2 = _packetProvider.SeekTo(samplePosition, 1, GetPacketGranules); num = (int)(samplePosition - num2); } ResetDecoder(); _hasPosition = true; if (!ReadNextPacket(0, out var samplePosition2)) { _eosFound = true; if (_packetProvider.GetGranuleCount() != samplePosition) { throw new InvalidOperationException("Could not read pre-roll packet! Try seeking again prior to reading more samples."); } _prevPacketStart = _prevPacketStop; _currentPosition = samplePosition; return; } if (!ReadNextPacket(0, out samplePosition2)) { ResetDecoder(); _eosFound = true; throw new InvalidOperationException("Could not read pre-roll packet! Try seeking again prior to reading more samples."); } _prevPacketStart += num; _currentPosition = samplePosition; } private int GetPacketGranules(IPacket curPacket) { if (curPacket.IsResync) { return 0; } if (curPacket.ReadBit()) { return 0; } int num = (int)curPacket.ReadBits(_modeFieldBits); if (num < 0 || num >= _modes.Length) { return 0; } return _modes[num].GetPacketSampleCount(curPacket); } public void Dispose() { (_packetProvider as IDisposable)?.Dispose(); _packetProvider = null; } } internal class StreamStats : IStreamStats { private int _sampleRate; private readonly int[] _packetBits = new int[2]; private readonly int[] _packetSamples = new int[2]; private int _packetIndex; private long _totalSamples; private long _audioBits; private long _headerBits; private long _containerBits; private long _wasteBits; private object _lock = new object(); private int _packetCount; public int EffectiveBitRate { get { long totalSamples; long num; lock (_lock) { totalSamples = _totalSamples; num = _audioBits + _headerBits + _containerBits + _wasteBits; } if (totalSamples > 0) { return (int)((double)num / (double)totalSamples * (double)_sampleRate); } return 0; } } public int InstantBitRate { get { int num; int num2; lock (_lock) { num = _packetBits[0] + _packetBits[1]; num2 = _packetSamples[0] + _packetSamples[1]; } if (num2 > 0) { return (int)((double)num / (double)num2 * (double)_sampleRate); } return 0; } } public long ContainerBits => _containerBits; public long OverheadBits => _headerBits; public long AudioBits => _audioBits; public long WasteBits => _wasteBits; public int PacketCount => _packetCount; public void ResetStats() { lock (_lock) { _packetBits[0] = (_packetBits[1] = 0); _packetSamples[0] = (_packetSamples[1] = 0); _packetIndex = 0; _packetCount = 0; _audioBits = 0L; _totalSamples = 0L; _headerBits = 0L; _containerBits = 0L; _wasteBits = 0L; } } internal void SetSampleRate(int sampleRate) { lock (_lock) { _sampleRate = sampleRate; ResetStats(); } } internal void AddPacket(int samples, int bits, int waste, int container) { lock (_lock) { if (samples >= 0) { _audioBits += bits; _wasteBits += waste; _containerBits += container; _totalSamples += samples; _packetBits[_packetIndex] = bits + waste; _packetSamples[_packetIndex] = samples; if (++_packetIndex == 2) { _packetIndex = 0; } } else { _headerBits += bits; _wasteBits += waste; _containerBits += container; } } } } internal class TagData : ITagData { private static IReadOnlyList<string> s_emptyList = new List<string>(); private Dictionary<string, IReadOnlyList<string>> _tags; public IReadOnlyDictionary<string, IReadOnlyList<string>> All => _tags; public string EncoderVendor { get; } public string Title => GetTagSingle("TITLE"); public string Version => GetTagSingle("VERSION"); public string Album => GetTagSingle("ALBUM"); public string TrackNumber => GetTagSingle("TRACKNUMBER"); public string Artist => GetTagSingle("ARTIST"); public IReadOnlyList<string> Performers => GetTagMulti("PERFORMER"); public string Copyright => GetTagSingle("COPYRIGHT"); public string License => GetTagSingle("LICENSE"); public string Organization => GetTagSingle("ORGANIZATION"); public string Description => GetTagSingle("DESCRIPTION"); public IReadOnlyList<string> Genres => GetTagMulti("GENRE"); public IReadOnlyList<string> Dates => GetTagMulti("DATE"); public IReadOnlyList<string> Locations => GetTagMulti("LOCATION"); public string Contact => GetTagSingle("CONTACT"); public string Isrc => GetTagSingle("ISRC"); public TagData(string vendor, string[] comments) { EncoderVendor = vendor; Dictionary<string, IReadOnlyList<string>> dictionary = new Dictionary<string, IReadOnlyList<string>>(); for (int i = 0; i < comments.Length; i++) { string[] array = comments[i].Split(new char[1] { '=' }); if (array.Length == 1) { array = new string[2] { array[0], string.Empty }; } int num = array[0].IndexOf('['); if (num > -1) { array[1] = array[0].Substring(num + 1, array[0].Length - num - 2).ToUpper(CultureInfo.CurrentCulture) + ": " + array[1]; array[0] = array[0].Substring(0, num); } if (dictionary.TryGetValue(array[0].ToUpperInvariant(), out var value)) { ((List<string>)value).Add(array[1]); continue; } dictionary.Add(array[0].ToUpperInvariant(), new List<string> { array[1] }); } _tags = dictionary; } public string GetTagSingle(string key, bool concatenate = false) { IReadOnlyList<string> tagMulti = GetTagMulti(key); if (tagMulti.Count > 0) { if (concatenate) { return string.Join(Environment.NewLine, tagMulti.ToArray()); } return tagMulti[tagMulti.Count - 1]; } return string.Empty; } public IReadOnlyList<string> GetTagMulti(string key) { if (_tags.TryGetValue(key.ToUpperInvariant(), out var value)) { return value; } return s_emptyList; } } internal static class Utils { internal static int ilog(int x) { int num = 0; while (x > 0) { num++; x >>= 1; } return num; } internal static uint BitReverse(uint n) { return BitReverse(n, 32); } internal static uint BitReverse(uint n, int bits) { n = ((n & 0xAAAAAAAAu) >> 1) | ((n & 0x55555555) << 1); n = ((n & 0xCCCCCCCCu) >> 2) | ((n & 0x33333333) << 2); n = ((n & 0xF0F0F0F0u) >> 4) | ((n & 0xF0F0F0F) << 4); n = ((n & 0xFF00FF00u) >> 8) | ((n & 0xFF00FF) << 8); return ((n >> 16) | (n << 16)) >> 32 - bits; } internal static float ClipValue(float value, ref bool clipped) { if (value > MathF.PI * 113f / 355f) { clipped = true; return MathF.PI * 113f / 355f; } if (value < MathF.PI * -113f / 355f) { clipped = true; return MathF.PI * -113f / 355f; } return value; } internal static float ConvertFromVorbisFloat32(uint bits) { int num = (int)bits >> 31; double y = (int)(((bits & 0x7FE00000) >> 21) - 788); return (float)(((bits & 0x1FFFFF) ^ num) + (num & 1)) * (float)Math.Pow(2.0, y); } } public sealed class VorbisReader : IVorbisReader, IDisposable { private readonly List<IStreamDecoder> _decoders; private readonly NVorbis.Contracts.IContainerReader _containerReader; private readonly bool _closeOnDispose; private IStreamDecoder _streamDecoder; internal static Func<Stream, bool, NVorbis.Contracts.IContainerReader> CreateContainerReader { get; set; } = (Stream s, bool cod) => new ContainerReader(s, cod); internal static Func<NVorbis.Contracts.IPacketProvider, IStreamDecoder> CreateStreamDecoder { get; set; } = (NVorbis.Contracts.IPacketProvider pp) => new StreamDecoder(pp, new Factory()); public IReadOnlyList<IStreamDecoder> Streams => _decoders; public int Channels => _streamDecoder.Channels; public int SampleRate => _streamDecoder.SampleRate; public int UpperBitrate => _streamDecoder.UpperBitrate; public int NominalBitrate => _streamDecoder.NominalBitrate; public int LowerBitrate => _streamDecoder.LowerBitrate; public ITagData Tags => _streamDecoder.Tags; [Obsolete("Use .Tags.EncoderVendor instead.")] public string Vendor => _streamDecoder.Tags.EncoderVendor; [Obsolete("Use .Tags.All instead.")] public string[] Comments => _streamDecoder.Tags.All.SelectMany((KeyValuePair<string, IReadOnlyList<string>> k) => k.Value, (KeyValuePair<string, IReadOnlyList<string>> kvp, string Item) => kvp.Key + "=" + Item).ToArray(); [Obsolete("No longer supported. Will receive a new stream when parameters change.", true)] public bool IsParameterChange { get { throw new NotSupportedException(); } } public long ContainerOverheadBits => _containerReader?.ContainerBits ?? 0; public long ContainerWasteBits => _containerReader?.WasteBits ?? 0; public int StreamIndex => _decoders.IndexOf(_streamDecoder); [Obsolete("Use .Streams.Count instead.")] public int StreamCount => _decoders.Count; [Obsolete("Use VorbisReader.TimePosition instead.")] public TimeSpan DecodedTime { get { return _streamDecoder.TimePosition; } set { TimePosition = value; } } [Obsolete("Use VorbisReader.SamplePosition instead.")] public long DecodedPosition { get { return _streamDecoder.SamplePosition; } set { SamplePosition = value; } } public TimeSpan TotalTime => _streamDecoder.TotalTime; public long TotalSamples => _streamDecoder.TotalSamples; public TimeSpan TimePosition { get { return _streamDecoder.TimePosition; } set { _streamDecoder.TimePosition = value; } } public long SamplePosition { get { return _streamDecoder.SamplePosition; } set { _streamDecoder.SamplePosition = value; } } public bool IsEndOfStream => _streamDecoder.IsEndOfStream; public bool ClipSamples { get { return _streamDecoder.ClipSamples; } set { _streamDecoder.ClipSamples = value; } } public bool HasClipped => _streamDecoder.HasClipped; public IStreamStats StreamStats => _streamDecoder.Stats; [Obsolete("Use Streams[*].Stats instead.", true)] public IVorbisStreamStatus[] Stats { get { throw new NotSupportedException(); } } public event EventHandler<NewStreamEventArgs> NewStream; public VorbisReader(string fileName) : this(File.OpenRead(fileName)) { } public VorbisReader(Stream stream, bool closeOnDispose = true) { _decoders = new List<IStreamDecoder>(); NVorbis.Contracts.IContainerReader containerReader = CreateContainerReader(stream, closeOnDispose); containerReader.NewStreamCallback = ProcessNewStream; if (!containerReader.TryInit() || _decoders.Count == 0) { containerReader.NewStreamCallback = null; containerReader.Dispose(); if (closeOnDispose) { stream.Dispose(); } throw new ArgumentException("Could not load the specified container!", "containerReader"); } _closeOnDispose = closeOnDispose; _containerReader = containerReader; _streamDecoder = _decoders[0]; } [Obsolete("Use \"new StreamDecoder(Contracts.IPacketProvider)\" and the container's NewStreamCallback or Streams property instead.", true)] public VorbisReader(NVorbis.Contracts.IContainerReader containerReader) { throw new NotSupportedException(); } [Obsolete("Use \"new StreamDecoder(Contracts.IPacketProvider)\" instead.", true)] public VorbisReader(NVorbis.Contracts.IPacketProvider packetProvider) { throw new NotSupportedException(); } private bool ProcessNewStream(NVorbis.Contracts.IPacketProvider packetProvider) { IStreamDecoder streamDecoder = CreateStreamDecoder(packetProvider); streamDecoder.ClipSamples = true; NewStreamEventArgs newStreamEventArgs = new NewStreamEventArgs(streamDecoder); this.NewStream?.Invoke(this, newStreamEventArgs); if (!newStreamEventArgs.IgnoreStream) { _decoders.Add(streamDecoder); return true; } return false; } public void Dispose() { if (_decoders != null) { foreach (IStreamDecoder decoder in _decoders) { decoder.Dispose(); } _decoders.Clear(); } if (_containerReader != null) { _containerReader.NewStreamCallback = null; if (_closeOnDispose) { _containerReader.Dispose(); } } } public bool FindNextStream() { if (_containerReader == null) { return false; } return _containerReader.FindNextStream(); } public bool SwitchStreams(int index) { if (index < 0 || index >= _decoders.Count) { throw new ArgumentOutOfRangeException("index"); } IStreamDecoder streamDecoder = _decoders[index]; IStreamDecoder streamDecoder2 = _streamDecoder; if (streamDecoder == streamDecoder2) { return false; } streamDecoder.ClipSamples = streamDecoder2.ClipSamples; _streamDecoder = streamDecoder; if (streamDecoder.Channels == streamDecoder2.Channels) { return streamDecoder.SampleRate != streamDecoder2.SampleRate; } return true; } public void SeekTo(TimeSpan timePosition, SeekOrigin seekOrigin = SeekOrigin.Begin) { _streamDecoder.SeekTo(timePosition, seekOrigin); } public void SeekTo(long samplePosition, SeekOrigin seekOrigin = SeekOrigin.Begin) { _streamDecoder.SeekTo(samplePosition, seekOrigin); } public int ReadSamples(float[] buffer, int offset, int count) { count -= count % _streamDecoder.Channels; if (count > 0) { return _streamDecoder.Read(buffer, offset, count); } return 0; } public int ReadSamples(Span<float> buffer) { int count = buffer.Length - buffer.Length % _streamDecoder.Channels; if (!buffer.IsEmpty) { return _streamDecoder.Read(buffer, 0, count); } return 0; } [Obsolete("No longer needed.", true)] public void ClearParameterChange() { throw new NotSupportedException(); } } } namespace NVorbis.Ogg { public sealed class ContainerReader : NVorbis.Contracts.IContainerReader, IDisposable { private IPageReader _reader; private List<WeakReference<NVorbis.Contracts.IPacketProvider>> _packetProviders; private bool _foundStream; internal static Func<Stream, bool, Func<NVorbis.Contracts.IPacketProvider, bool>, IPageReader> CreatePageReader { get; set; } = (Stream s, bool cod, Func<NVorbis.Contracts.IPacketProvider, bool> cb) => new PageReader(s, cod, cb); internal static Func<Stream, bool, Func<NVorbis.Contracts.IPacketProvider, bool>, IPageReader> CreateForwardOnlyPageReader { get; set; } = (Stream s, bool cod, Func<NVorbis.Contracts.IPacketProvider, bool> cb) => new ForwardOnlyPageReader(s, cod, cb); public NewStreamHandler NewStreamCallback { get; set; } public bool CanSeek { get; } public long WasteBits => _reader.WasteBits; public long ContainerBits => _reader.ContainerBits; public IReadOnlyList<NVorbis.Contracts.IPacketProvider> GetStreams() { List<NVorbis.Contracts.IPacketProvider> list = new List<NVorbis.Contracts.IPacketProvider>(_packetProviders.Count); for (int i = 0; i < _packetProviders.Count; i++) { if (_packetProviders[i].TryGetTarget(out var target)) { list.Add(target); continue; } list.RemoveAt(i); i--; } return list; } public ContainerReader(Stream stream, bool closeOnDispose) { if (stream == null) { throw new ArgumentNullException("stream"); } _packetProviders = new List<WeakReference<NVorbis.Contracts.IPacketProvider>>(); if (stream.CanSeek) { _reader = CreatePageReader(stream, closeOnDispose, ProcessNewStream); CanSeek = true; } else { _reader = CreateForwardOnlyPageReader(stream, closeOnDispose, ProcessNewStream); } } public bool TryInit() { return FindNextStream(); } public bool FindNextStream() { _reader.Lock(); try { _foundStream = false; while (_reader.ReadNextPage()) { if (_foundStream) { return true; } } return false; } finally { _reader.Release(); } } private bool ProcessNewStream(NVorbis.Contracts.IPacketProvider packetProvider) { bool flag = _reader.Release(); try { NewStreamHandler newStreamCallback = NewStreamCallback; if (newStreamCallback == null || newStreamCallback(packetProvider)) { _packetProviders.Add(new WeakReference<NVorbis.Contracts.IPacketProvider>(packetProvider)); _foundStream = true; return true; } return false; } finally { if (flag) { _reader.Lock(); } } } public void Dispose() { _reader?.Dispose(); _reader = null; } } internal class Crc : ICrc { private const uint CRC32_POLY = 79764919u; private static readonly uint[] s_crcTable; private uint _crc; static Crc() { s_crcTable = new uint[256]; for (uint num = 0u; num < 256; num++) { uint num2 = num << 24; for (int i = 0; i < 8; i++) { num2 = (num2 << 1) ^ ((num2 >= 2147483648u) ? 79764919u : 0u); } s_crcTable[num] = num2; } } public Crc() { Reset(); } public void Reset() { _crc = 0u; } public void Update(int nextVal) { _crc = (_crc << 8) ^ s_crcTable[nextVal ^ (_crc >> 24)]; } public bool Test(uint checkCrc) { return _crc == checkCrc; } } internal class ForwardOnlyPacketProvider : DataPacket, IForwardOnlyPacketProvider, NVorbis.Contracts.IPacketProvider { private int _lastSeqNo; private readonly Queue<(byte[] buf, bool isResync)> _pageQueue = new Queue<(byte[], bool)>(); private readonly IPageReader _reader; private byte[] _pageBuf; private int _packetIndex; private bool _isEndOfStream; private int _dataStart; private bool _lastWasPeek; private Memory<byte> _packetBuf; private int _dataIndex; public bool CanSeek => false; public int StreamSerial { get; } protected override int TotalBits => _packetBuf.Length * 8; public ForwardOnlyPacketProvider(IPageReader reader, int streamSerial) { _reader = reader; StreamSerial = streamSerial; _packetIndex = int.MaxValue; } public bool AddPage(byte[] buf, bool isResync) { if ((buf[5] & 2u) != 0) { if (_isEndOfStream) { return false; } isResync = true; _lastSeqNo = BitConverter.ToInt32(buf, 18); } else { int num = BitConverter.ToInt32(buf, 18); isResync |= num != _lastSeqNo + 1; _lastSeqNo = num; } int num2 = 0; for (int i = 0; i < buf[26]; i++) { num2 += buf[27 + i]; } if (num2 == 0) { return false; } _pageQueue.Enqueue((buf, isResync)); return true; } public void SetEndOfStream() { _isEndOfStream = true; } public IPacket GetNextPacket() { if (_packetBuf.Length > 0) { if (!_lastWasPeek) { throw new InvalidOperationException("Must call Done() on previous packet first."); } _lastWasPeek = false; return this; } _lastWasPeek = false; if (GetPacket()) { return this; } return null; } public IPacket PeekNextPacket() { if (_packetBuf.Length > 0) { if (!_lastWasPeek) { throw new InvalidOperationException("Must call Done() on previous packet first."); } return this; } _lastWasPeek = true; if (GetPacket()) { return this; } return null; } private bool GetPacket() { byte[] pageBuf; bool isResync; int packetIndex; bool isContinuation; bool isContinued; int dataStart; if (_pageBuf != null && _packetIndex < 27 + _pageBuf[26]) { pageBuf = _pageBuf; isResync = false; dataStart = _dataStart; packetIndex = _packetIndex; isContinuation = false; isContinued = pageBuf[26 + pageBuf[26]] == byte.MaxValue; } else if (!ReadNextPage(out pageBuf, out isResync, out dataStart, out packetIndex, out isContinuation, out isContinued)) { return false; } int num = dataStart; bool flag = packetIndex == 27; if (isContinuation && flag) { isResync = true; num += GetPacketLength(pageBuf, ref packetIndex); if (packetIndex == 27 + pageBuf[26]) { return GetPacket(); } } if (!flag) { num = 0; } int packetLength = GetPacketLength(pageBuf, ref packetIndex); Memory<byte> memory = new Memory<byte>(pageBuf, dataStart, packetLength); dataStart += packetLength; bool flag2 = packetIndex == 27 + pageBuf[26]; if (isContinued) { if (flag2) { flag2 = false; } else { int packetIndex2 = packetIndex; GetPacketLength(pageBuf, ref packetIndex2); flag2 = packetIndex2 == 27 + pageBuf[26]; } } bool flag3 = false; long? granulePosition = null; if (flag2) { granulePosition = BitConverter.ToInt64(pageBuf, 6); if ((pageBuf[5] & 4u) != 0 || (_isEndOfStream && _pageQueue.Count == 0)) { flag3 = true; } } else { while (isContinued && packetIndex == 27 + pageBuf[26] && ReadNextPage(out pageBuf, out isResync, out dataStart, out packetIndex, out isContinuation, out isContinued) && !isResync && isContinuation) { num += 27 + pageBuf[26]; Memory<byte> memory2 = memory; int packetLength2 = GetPacketLength(pageBuf, ref packetIndex); memory = new Memory<byte>(new byte[memory2.Length + packetLength2]); memory2.CopyTo(memory); new Memory<byte>(pageBuf, dataStart, packetLength2).CopyTo(memory.Slice(memory2.Length)); dataStart += packetLength2; } } base.IsResync = isResync; base.GranulePosition = granulePosition; base.IsEndOfStream = flag3; base.ContainerOverheadBits = num * 8; _pageBuf = pageBuf; _dataStart = dataStart; _packetIndex = packetIndex; _packetBuf = memory; _isEndOfStream |= flag3; Reset(); return true; } private bool ReadNextPage(out byte[] pageBuf, out bool isResync, out int dataStart, out int packetIndex, out bool isContinuation, out bool isContinued) { while (_pageQueue.Count == 0) { if (_isEndOfStream || !_reader.ReadNextPage()) { pageBuf = null; isResync = false; dataStart = 0; packetIndex = 0; isContinuation = false; isContinued = false; return false; } } (byte[], bool) tuple = _pageQueue.Dequeue(); pageBuf = tuple.Item1; isResync = tuple.Item2; dataStart = pageBuf[26] + 27; packetIndex = 27; isContinuation = (pageBuf[5] & 1) != 0; isContinued = pageBuf[26 + pageBuf[26]] == byte.MaxValue; return true; } private int GetPacketLength(byte[] pageBuf, ref int packetIndex) { int num = 0;
plugins/RockHero.dll
Decompiled 3 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using Concentus; using Concentus.Oggfile; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Microsoft.CodeAnalysis; using NVorbis; using RockHero.Charts; using RockHero.World; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("RockHero")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Rock Hero style rhythm game in the Big Walk world, playing Clone Hero / Enchor charts.")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0")] [assembly: AssemblyProduct("RockHero")] [assembly: AssemblyTitle("RockHero")] [assembly: AssemblyVersion("0.1.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace RockHero { internal sealed class PcmData { public float[] Samples; public int SampleRate; public int Frames; } internal static class AudioLoader { private const int OpusRate = 48000; private static readonly string[] Extensions = new string[2] { ".ogg", ".opus" }; public static PcmData Load(string dir, out string error) { //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Expected O, but got Unknown error = null; List<string> list = new List<string>(); string text = null; string[] extensions = Extensions; foreach (string text2 in extensions) { string text3 = Path.Combine(dir, "song" + text2); if (File.Exists(text3)) { text = text3; break; } } if (text != null) { list.Add(text); } else { string[] files = Directory.GetFiles(dir); foreach (string text4 in files) { string value = Path.GetExtension(text4).ToLowerInvariant(); if (Array.IndexOf(Extensions, value) >= 0) { string text5 = Path.GetFileNameWithoutExtension(text4).ToLowerInvariant(); if (!text5.Contains("crowd") && !text5.Contains("preview")) { list.Add(text4); } } } } if (list.Count == 0) { error = "No .ogg/.opus audio in the song folder (mp3/wav are not supported yet)."; return null; } float[] mix = null; int rate = 0; int frames = 0; bool flag = default(bool); foreach (string item in list) { try { if (IsOpus(item)) { DecodeOpus(item, ref mix, ref rate, ref frames); } else { DecodeVorbis(item, ref mix, ref rate, ref frames); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(19, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Could not decode "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(Path.GetFileName(item)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogWarning(val); } } if (mix == null || frames == 0) { error = "Could not decode any audio in the song folder."; return null; } int num = frames * 2; for (int k = 0; k < num; k++) { float num2 = mix[k]; mix[k] = ((num2 > 1f) ? 1f : ((num2 < -1f) ? (-1f) : num2)); } return new PcmData { Samples = mix, SampleRate = rate, Frames = frames }; } private static bool IsOpus(string path) { using (FileStream fileStream = File.OpenRead(path)) { byte[] array = new byte[128]; int num = fileStream.Read(array, 0, array.Length); for (int i = 0; i + 8 <= num; i++) { if (array[i] == 79 && array[i + 1] == 112 && array[i + 2] == 117 && array[i + 3] == 115 && array[i + 4] == 72 && array[i + 5] == 101 && array[i + 6] == 97 && array[i + 7] == 100) { return true; } } } return false; } private static void Grow(ref float[] mix, int needed) { if (mix == null) { mix = new float[Math.Max(needed, 1048576)]; } else if (mix.Length < needed) { Array.Resize(ref mix, Math.Max(needed, mix.Length + mix.Length / 2)); } } private static void DecodeOpus(string path, ref float[] mix, ref int rate, ref int frames) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown if (rate == 0) { rate = 48000; } else if (rate != 48000) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(42, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Skipping stem with different sample rate: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(Path.GetFileName(path)); } log.LogWarning(val); return; } using FileStream fileStream = File.OpenRead(path); IOpusDecoder val2 = OpusCodecFactory.CreateDecoder(48000, 2, (TextWriter)null); OpusOggReadStream val3 = new OpusOggReadStream(val2, (Stream)fileStream); int num = 0; while (val3.HasNextPacket) { short[] array = val3.DecodeNextPacket(); if (array != null && array.Length != 0) { Grow(ref mix, num + array.Length); for (int i = 0; i < array.Length; i++) { mix[num + i] += (float)array[i] * 3.0517578E-05f; } num += array.Length; } } frames = Math.Max(frames, num / 2); } private static void DecodeVorbis(string path, ref float[] mix, ref int rate, ref int frames) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown VorbisReader val = new VorbisReader(path); try { int channels = val.Channels; if (channels <= 0) { return; } if (rate == 0) { rate = val.SampleRate; } else if (val.SampleRate != rate) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(42, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Skipping stem with different sample rate: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(Path.GetFileName(path)); } log.LogWarning(val2); return; } long totalSamples = val.TotalSamples; if (totalSamples <= 0) { return; } int num = (int)Math.Min(totalSamples, 1073741822L); Grow(ref mix, num * 2); frames = Math.Max(frames, num); float[] array = new float[4096 * channels]; int num3; for (int i = 0; i < num; i += num3) { int num2; if ((num2 = val.ReadSamples(array, 0, array.Length)) <= 0) { break; } num3 = num2 / channels; if (i + num3 > num) { num3 = num - i; } int num4 = i * 2; if (channels == 1) { for (int j = 0; j < num3; j++) { float num5 = array[j]; mix[num4++] += num5; mix[num4++] += num5; } continue; } int num6 = 0; int num7 = 0; while (num6 < num3) { mix[num4++] += array[num7]; mix[num4++] += array[num7 + 1]; num6++; num7 += channels; } } } finally { ((IDisposable)val)?.Dispose(); } } } [BepInPlugin("bigwalk.rockhero", "RockHero", "0.1.0")] public class Plugin : BasePlugin { public const string Guid = "bigwalk.rockhero"; public const string Name = "RockHero"; public const string Version = "0.1.0"; internal static ManualLogSource Log; internal static ConfigEntry<KeyCode> MenuKey; internal static ConfigEntry<KeyCode> StopKey; internal static ConfigEntry<KeyCode> OverdriveKey; internal static ConfigEntry<float> OverdriveFullBarSeconds; internal static readonly ConfigEntry<KeyCode>[] FretKeys = new ConfigEntry<KeyCode>[5]; internal static ConfigEntry<string> SongsFolder; internal static ConfigEntry<string> Difficulty; internal static ConfigEntry<string> InstrumentName; internal static ConfigEntry<float> HighwayWidth; internal static ConfigEntry<float> HighwayLength; internal static ConfigEntry<float> HighwaySpeed; internal static ConfigEntry<float> StrikeHeight; internal static ConfigEntry<float> TiltDegrees; internal static ConfigEntry<float> PlaceDistance; internal static ConfigEntry<float> AudioOffsetMs; internal static ConfigEntry<float> HitWindowMs; internal static ConfigEntry<float> LeadInSeconds; internal static ConfigEntry<bool> PenalizeExtraPresses; internal static ConfigEntry<float> Volume; public override void Load() { //IL_050e: Unknown result type (might be due to invalid IL or missing references) //IL_0515: Expected O, but got Unknown //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Expected O, but got Unknown //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Expected O, but got Unknown //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Expected O, but got Unknown //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Expected O, but got Unknown //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Expected O, but got Unknown //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Expected O, but got Unknown //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Expected O, but got Unknown //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Expected O, but got Unknown //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Expected O, but got Unknown //IL_03ce: Unknown result type (might be due to invalid IL or missing references) //IL_03d8: Expected O, but got Unknown //IL_040b: Unknown result type (might be due to invalid IL or missing references) //IL_0415: Expected O, but got Unknown //IL_0468: Unknown result type (might be due to invalid IL or missing references) //IL_0472: Expected O, but got Unknown //IL_04a5: Unknown result type (might be due to invalid IL or missing references) //IL_04af: Expected O, but got Unknown //IL_054d: Unknown result type (might be due to invalid IL or missing references) //IL_0553: Expected O, but got Unknown //IL_0576: Unknown result type (might be due to invalid IL or missing references) //IL_057d: Expected O, but got Unknown //IL_04d0: Unknown result type (might be due to invalid IL or missing references) //IL_04d7: Expected O, but got Unknown //IL_05bc: Unknown result type (might be due to invalid IL or missing references) Log = ((BasePlugin)this).Log; MenuKey = ((BasePlugin)this).Config.Bind<KeyCode>("Keys", "Menu", (KeyCode)290, "Open/close the song menu (also leaves the results screen)."); StopKey = ((BasePlugin)this).Config.Bind<KeyCode>("Keys", "Stop", (KeyCode)291, "Stop the current song."); OverdriveKey = ((BasePlugin)this).Config.Bind<KeyCode>("Keys", "Overdrive", (KeyCode)32, "Activate overdrive (star power) once the meter is at least half full."); KeyCode[] array = new KeyCode[5]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); KeyCode[] array2 = (KeyCode[])(object)array; string[] array3 = new string[5] { "Green", "Red", "Yellow", "Blue", "Orange" }; for (int i = 0; i < 5; i++) { FretKeys[i] = ((BasePlugin)this).Config.Bind<KeyCode>("Keys", "Fret" + (i + 1) + "_" + array3[i], array2[i], "Key for the " + array3[i].ToLowerInvariant() + " fret. Press when the note reaches the strike line."); } SongsFolder = ((BasePlugin)this).Config.Bind<string>("Songs", "Folder", "", "Folder holding extracted Clone Hero / Enchor song folders (each with notes.chart or notes.mid + .ogg audio). Empty uses a 'Songs' folder right next to RockHero.dll (inside the mod's own plugin folder)."); Difficulty = ((BasePlugin)this).Config.Bind<string>("Songs", "Difficulty", "Expert", new ConfigDescription("Expert, Hard, Medium or Easy. Falls back to the next lower one if the chart lacks it.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[4] { "Expert", "Hard", "Medium", "Easy" }), Array.Empty<object>())); InstrumentName = ((BasePlugin)this).Config.Bind<string>("Songs", "Instrument", "Guitar", new ConfigDescription("Guitar, Bass, Rhythm, Coop or Keys. Switch in the song menu with Left/Right.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[5] { "Guitar", "Bass", "Rhythm", "Coop", "Keys" }), Array.Empty<object>())); HighwayWidth = ((BasePlugin)this).Config.Bind<float>("Highway", "WidthMeters", 2f, new ConfigDescription("Width of the 5-lane highway.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 8f), Array.Empty<object>())); HighwayLength = ((BasePlugin)this).Config.Bind<float>("Highway", "LengthMeters", 5f, new ConfigDescription("Length of the highway (how far ahead you see notes).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1.5f, 20f), Array.Empty<object>())); HighwaySpeed = ((BasePlugin)this).Config.Bind<float>("Highway", "SpeedMetersPerSecond", 3f, new ConfigDescription("Note scroll speed. Length / speed = seconds of look-ahead.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 12f), Array.Empty<object>())); StrikeHeight = ((BasePlugin)this).Config.Bind<float>("Highway", "StrikeLineHeightMeters", 0.5f, new ConfigDescription("Height of the strike line above the ground.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 5f), Array.Empty<object>())); TiltDegrees = ((BasePlugin)this).Config.Bind<float>("Highway", "TiltDegrees", 66.4f, new ConfigDescription("How far the far end of the highway leans away from you.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 80f), Array.Empty<object>())); PlaceDistance = ((BasePlugin)this).Config.Bind<float>("Highway", "PlaceDistanceMeters", 3f, new ConfigDescription("How far in front of you the strike line is put when a song starts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 15f), Array.Empty<object>())); AudioOffsetMs = ((BasePlugin)this).Config.Bind<float>("Timing", "AudioOffsetMs", 0f, new ConfigDescription("Latency calibration. Positive = notes come later (use if you hit early), negative = earlier.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-500f, 500f), Array.Empty<object>())); HitWindowMs = ((BasePlugin)this).Config.Bind<float>("Timing", "HitWindowMs", 150f, new ConfigDescription("Hit window either side of a note.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(50f, 300f), Array.Empty<object>())); LeadInSeconds = ((BasePlugin)this).Config.Bind<float>("Timing", "LeadInSeconds", 3f, new ConfigDescription("Count-in before the audio starts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>())); PenalizeExtraPresses = ((BasePlugin)this).Config.Bind<bool>("Timing", "PenalizeExtraPresses", false, "Break your streak when you press a fret with no note to hit."); OverdriveFullBarSeconds = ((BasePlugin)this).Config.Bind<float>("Overdrive", "FullBarSeconds", 16f, new ConfigDescription("How long a completely full meter lasts once activated. Each star phrase fills 25%.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(4f, 60f), Array.Empty<object>())); Volume = ((BasePlugin)this).Config.Bind<float>("Audio", "Volume", 0.8f, new ConfigDescription("Song volume (0-1).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val; try { string text = ResolveSongsFolder(); Directory.CreateDirectory(text); ManualLogSource log = Log; val = new BepInExInfoLogInterpolatedStringHandler(14, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Songs folder: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text); } log.LogInfo(val); } catch (Exception ex) { ManualLogSource log2 = Log; BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(35, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Could not create the songs folder: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message); } log2.LogWarning(val2); } ClassInjector.RegisterTypeInIl2Cpp<RhythmController>(); GameObject val3 = new GameObject("RockHero"); ((Object)val3).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)val3); val3.AddComponent<RhythmController>(); ManualLogSource log3 = Log; val = new BepInExInfoLogInterpolatedStringHandler(32, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("RockHero"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" v"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("0.1.0"); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded. "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<KeyCode>(MenuKey.Value); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" opens the song menu."); } log3.LogInfo(val); } internal static string ResolveSongsFolder() { string value = SongsFolder.Value; if (!string.IsNullOrWhiteSpace(value)) { return value.Trim(); } string text = null; try { string location = typeof(Plugin).Assembly.Location; if (!string.IsNullOrEmpty(location)) { text = Path.GetDirectoryName(location); } } catch { } if (string.IsNullOrEmpty(text)) { text = Path.Combine(Paths.PluginPath, "RockHero"); } return Path.Combine(text, "Songs"); } public override bool Unload() { RhythmGame.Instance.Shutdown(); return true; } } public sealed class RhythmController : MonoBehaviour { public RhythmController(IntPtr ptr) : base(ptr) { } public void Update() { RhythmGame.Instance.Tick(); } public void OnGUI() { RhythmGame.Instance.Draw(); } } internal sealed class RhythmGame { private enum Phase { Idle, Loading, Uploading, Playing, Finished } private sealed class LoadResult { public int Gen; public SongInfo Song; public Chart Chart; public PcmData Pcm; public string Error; } public static readonly RhythmGame Instance = new RhythmGame(); private const int UploadChunkFrames = 131072; private const int ChunksPerFrame = 2; private readonly Highway _highway = new Highway(); private Phase _phase = Phase.Idle; private bool _menuOpen; private bool _menuDirty = true; private bool _hudDirty = true; private string _menuText = ""; private string _hud = ""; private string _results = ""; private string _status = ""; private string _songFolder = ""; private List<SongInfo> _allSongs = new List<SongInfo>(); private List<SongInfo> _songs = new List<SongInfo>(); private GuitarPart _instrument; private bool _instrumentInit; private string _playLabel = ""; private bool _scanned; private int _selected; private volatile LoadResult _loadResult; private int _gen; private SongInfo _song; private Chart _chart; private PcmData _pcm; private int _uploadFrame; private AudioClip _clip; private GameObject _audioGO; private AudioSource _source; private double _startDsp; private double _clipSeconds; private double _endTime; private double _t; private bool _clockInit; private byte[] _chordState; private byte[] _hitMask; private int _cursor; private int _score; private int _streak; private int _bestStreak; private int _hitChords; private int _missChords; private double _hitWindow; private readonly KeyCode[] _fretKeys = (KeyCode[])(object)new KeyCode[5]; private readonly bool[] _held = new bool[5]; private GUIStyle _label; private GUIStyle _box; private bool _loggedError; private const int NotePoints = 50; private const double SustainPointsPerSecond = 50.0; private const double SustainReleaseGrace = 0.1; private const float PhraseEnergy = 0.25f; private const float OverdriveMinEnergy = 0.5f; private float _energy; private bool _spActive; private KeyCode _spKey; private double _odSeconds; private readonly int[] _susNote = new int[5]; private double _susAcc; private bool[] _phraseBroken; private float _hudNext; private int Multiplier => Math.Min(4, 1 + _streak / 10); private int EffectiveMultiplier => Multiplier * ((!_spActive) ? 1 : 2); public void Tick() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) try { if (Input.GetKeyDown(Plugin.MenuKey.Value)) { ToggleMenu(); } if (_phase != Phase.Idle && Input.GetKeyDown(Plugin.StopKey.Value)) { Stop(); } if (_menuOpen && _phase == Phase.Idle) { HandleMenuInput(); } switch (_phase) { case Phase.Loading: PollLoad(); break; case Phase.Uploading: TickUpload(); break; case Phase.Playing: TickPlaying(); break; } } catch (Exception ex) { if (!_loggedError) { _loggedError = true; ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(13, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Tick failed: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex); } log.LogError(val); } } } private void ToggleMenu() { if (_phase == Phase.Finished) { CleanupSong(); _phase = Phase.Idle; _menuOpen = true; if (!_scanned) { Rescan(); } _menuDirty = true; } else if (_phase == Phase.Idle) { _menuOpen = !_menuOpen; if (_menuOpen && !_scanned) { Rescan(); } _menuDirty = true; } } private void Rescan() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown _songFolder = Plugin.ResolveSongsFolder(); _allSongs = SongLibrary.Scan(_songFolder); _scanned = true; if (!_instrumentInit) { _instrument = Instruments.Parse(Plugin.InstrumentName.Value); _instrumentInit = true; } ApplyFilter(); ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(25, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Found "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_allSongs.Count); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" songs in "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(_songFolder); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ("); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_songs.Count); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" with "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(Instruments.Label(_instrument)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")"); } log.LogInfo(val); } private void ApplyFilter() { string text = ((_selected >= 0 && _selected < _songs.Count) ? _songs[_selected].Dir : null); List<SongInfo> list = new List<SongInfo>(_allSongs.Count); for (int i = 0; i < _allSongs.Count; i++) { if (_allSongs[i].Supports(_instrument)) { list.Add(_allSongs[i]); } } _songs = list; _selected = 0; if (text != null) { for (int j = 0; j < _songs.Count; j++) { if (_songs[j].Dir == text) { _selected = j; break; } } } _menuDirty = true; } private void CycleInstrument(int dir) { _instrument = Instruments.Next(_instrument, dir); Plugin.InstrumentName.Value = _instrument.ToString(); ApplyFilter(); } private void CycleDifficulty() { int num = (ChartBuilder.StartIndex(Plugin.Difficulty.Value) + 1) % ChartBuilder.Difficulties.Length; Plugin.Difficulty.Value = ChartBuilder.Difficulties[num]; _menuDirty = true; } private void HandleMenuInput() { if (Input.GetKeyDown((KeyCode)275)) { CycleInstrument(1); } else if (Input.GetKeyDown((KeyCode)276)) { CycleInstrument(-1); } if (Input.GetKeyDown((KeyCode)9)) { CycleDifficulty(); } if (_songs.Count > 0) { if (Input.GetKeyDown((KeyCode)274)) { _selected = (_selected + 1) % _songs.Count; _menuDirty = true; } else if (Input.GetKeyDown((KeyCode)273)) { _selected = (_selected + _songs.Count - 1) % _songs.Count; _menuDirty = true; } else if (Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)271)) { StartSelected(); } } if (Input.GetKeyDown((KeyCode)114)) { Rescan(); } } private void RebuildMenuText() { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(768); stringBuilder.Append("ROCK HERO - ").Append(Instruments.Label(_instrument)).Append(" - ") .Append(Plugin.Difficulty.Value) .Append(" - ") .Append(_songs.Count) .Append(" songs\n"); stringBuilder.Append("Up/Down song Left/Right instrument Tab difficulty Enter play R rescan ").Append(Plugin.MenuKey.Value).Append(" close ") .Append(Plugin.StopKey.Value) .Append(" stop song\n\n"); if (_songs.Count == 0 && _allSongs.Count > 0) { stringBuilder.Append("None of your ").Append(_allSongs.Count).Append(" songs list a ") .Append(Instruments.Label(_instrument)) .Append(" part. Press Left/Right to pick another instrument."); } else if (_songs.Count == 0) { stringBuilder.Append("No songs found. Put song folders (each with notes.chart or notes.mid) under:\n").Append(_songFolder).Append("\n\n") .Append(SongLibrary.LastReport); } else { int num = Math.Max(0, Math.Min(_selected - 6, _songs.Count - 12)); int num2 = Math.Min(_songs.Count, num + 12); for (int i = num; i < num2; i++) { stringBuilder.Append((i == _selected) ? "> " : " ").Append(_songs[i].Display).Append('\n'); } } if (_status.Length > 0) { stringBuilder.Append('\n').Append(_status); } _menuText = stringBuilder.ToString(); } private void StartSelected() { SongInfo song = _songs[_selected]; string diff = Plugin.Difficulty.Value; GuitarPart instrument = _instrument; _playLabel = Instruments.Label(instrument) + " " + diff; _gen++; int gen = _gen; _loadResult = null; _song = song; _status = "Loading " + song.Display + "..."; _phase = Phase.Loading; _menuOpen = false; Thread thread = new Thread((ThreadStart)delegate { LoadWorker(song, instrument, diff, gen); }); thread.IsBackground = true; thread.Name = "RockHero.Load"; thread.Start(); } private void LoadWorker(SongInfo song, GuitarPart instrument, string diff, int gen) { LoadResult loadResult = new LoadResult { Gen = gen, Song = song }; try { loadResult.Chart = (song.IsMidi ? MidiFileParser.Load(song.ChartPath, instrument, diff, song.DelaySec, out var error) : ChartFileParser.Load(song.ChartPath, instrument, diff, song.DelaySec, out error)); if (loadResult.Chart == null) { loadResult.Error = error ?? "Chart parse failed."; } else { loadResult.Pcm = AudioLoader.Load(song.Dir, out error); if (loadResult.Pcm == null) { loadResult.Error = error ?? "Audio decode failed."; } } } catch (Exception ex) { loadResult.Error = ex.Message; } if (gen == _gen) { _loadResult = loadResult; } } private void PollLoad() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown LoadResult loadResult = _loadResult; if (loadResult == null) { return; } _loadResult = null; if (loadResult.Gen != _gen) { return; } if (loadResult.Error != null) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(19, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Could not load '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(loadResult.Song.Display); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(loadResult.Error); } log.LogWarning(val); _phase = Phase.Idle; _status = loadResult.Error; _menuOpen = true; _menuDirty = true; } else { _chart = loadResult.Chart; _pcm = loadResult.Pcm; _clip = AudioClip.Create("RockHero.Song", _pcm.Frames, 2, _pcm.SampleRate, false); _uploadFrame = 0; _phase = Phase.Uploading; } } private void TickUpload() { float[] samples = _pcm.Samples; int frames = _pcm.Frames; for (int i = 0; i < 2; i++) { if (_uploadFrame >= frames) { break; } int num = Math.Min(131072, frames - _uploadFrame); int num2 = num * 2; int num3 = _uploadFrame * 2; Il2CppStructArray<float> val = new Il2CppStructArray<float>((long)num2); for (int j = 0; j < num2; j++) { ((Il2CppArrayBase<float>)(object)val)[j] = samples[num3 + j]; } _clip.SetData(val, _uploadFrame); _uploadFrame += num; } _status = "Loading audio " + 100L * (long)_uploadFrame / frames + "%"; if (_uploadFrame >= frames) { StartPlayback(); } } private void StartPlayback() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Expected I4, but got Unknown if ((Object)(object)_audioGO == (Object)null) { _audioGO = new GameObject("RockHero.Audio"); Object.DontDestroyOnLoad((Object)(object)_audioGO); _source = _audioGO.AddComponent<AudioSource>(); _source.playOnAwake = false; _source.spatialBlend = 0f; _source.loop = false; } _source.clip = _clip; _source.volume = Plugin.Volume.Value; _clipSeconds = (double)_pcm.Frames / (double)_pcm.SampleRate; _pcm = null; if (!TryGetPlacement(out var pos, out var yaw)) { pos = Vector3.zero; yaw = 0f; Plugin.Log.LogWarning((object)"No camera found; highway placed at the world origin."); } _highway.Place(pos, yaw); _highway.SetChart(_chart); int num = _chart.Chords.Length; _chordState = new byte[num]; _hitMask = new byte[num]; _cursor = 0; _score = 0; _streak = 0; _bestStreak = 0; _hitChords = 0; _missChords = 0; _hitWindow = (double)Plugin.HitWindowMs.Value * 0.001; _energy = 0f; _spActive = false; _spKey = Plugin.OverdriveKey.Value; _odSeconds = Math.Max(1.0, Plugin.OverdriveFullBarSeconds.Value); for (int i = 0; i < 5; i++) { _susNote[i] = -1; } _susAcc = 0.0; _phraseBroken = new bool[_chart.PhraseCount]; _hudNext = 0f; for (int j = 0; j < 5; j++) { _fretKeys[j] = (KeyCode)(int)Plugin.FretKeys[j].Value; _held[j] = false; } _endTime = Math.Max(_chart.LastTime + 2.0, _clipSeconds); _hudDirty = true; _status = ""; double num2 = Math.Max(1.0, Plugin.LeadInSeconds.Value); _startDsp = AudioSettings.dspTime + num2; _source.PlayScheduled(_startDsp); _clockInit = false; _phase = Phase.Playing; } private static bool TryGetPlacement(out Vector3 pos, out float yaw) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) pos = Vector3.zero; yaw = 0f; Camera val = Camera.main; if ((Object)(object)val == (Object)null) { Il2CppReferenceArray<Camera> allCameras = Camera.allCameras; if (allCameras != null && ((Il2CppArrayBase<Camera>)(object)allCameras).Length > 0) { val = ((Il2CppArrayBase<Camera>)(object)allCameras)[0]; } } if ((Object)(object)val == (Object)null) { return false; } Transform transform = ((Component)val).transform; Vector3 forward = transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f) { forward = Vector3.forward; } ((Vector3)(ref forward)).Normalize(); Vector3 position = transform.position; Vector3 val2 = position + forward * Plugin.PlaceDistance.Value; float num = position.y - 1.5f; RaycastHit val3 = default(RaycastHit); if (Physics.Raycast(new Vector3(val2.x, position.y + 0.5f, val2.z), Vector3.down, ref val3, 20f)) { num = ((RaycastHit)(ref val3)).point.y; } pos = new Vector3(val2.x, num, val2.z); yaw = Mathf.Atan2(forward.x, forward.z) * 57.29578f; return true; } private void TickPlaying() { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) double num = Time.unscaledDeltaTime; double num2 = AudioSettings.dspTime - _startDsp - (double)Plugin.AudioOffsetMs.Value * 0.001; if (!_clockInit) { _t = num2; _clockInit = true; } else { _t += num; double num3 = num2 - _t; if (num3 > 0.05 || num3 < -0.05) { _t = num2; } else { _t += num3 * 0.1; } } for (int i = 0; i < 5; i++) { KeyCode val = _fretKeys[i]; bool key = Input.GetKey(val); if (key != _held[i]) { _held[i] = key; _highway.SetFretHeld(i, key); } if (Input.GetKeyDown(val)) { OnPress(i, _t); } } if (!_spActive && _energy >= 0.5f && Input.GetKeyDown(_spKey)) { _spActive = true; _hudDirty = true; } Chord[] chords = _chart.Chords; Note[] notes = _chart.Notes; int num4 = chords.Length; while (_cursor < num4) { if (_chordState[_cursor] != 0) { _cursor++; continue; } if (chords[_cursor].Time + _hitWindow >= _t) { break; } _chordState[_cursor] = 2; _streak = 0; _missChords++; int phrase = chords[_cursor].Phrase; if (phrase >= 0) { _phraseBroken[phrase] = true; } _hudDirty = true; _cursor++; } int effectiveMultiplier = EffectiveMultiplier; for (int j = 0; j < 5; j++) { int num5 = _susNote[j]; if (num5 >= 0) { double num6 = notes[num5].Time + notes[num5].Length; if (_t >= num6 || (!_held[j] && _t < num6 - 0.1)) { _susNote[j] = -1; } else { _susAcc += 50.0 * num * (double)effectiveMultiplier; } } } if (_susAcc >= 1.0) { int num7 = (int)_susAcc; _score += num7; _susAcc -= num7; _hudDirty = true; } if (_spActive) { _energy -= (float)(num / _odSeconds); if (_energy <= 0f) { _energy = 0f; _spActive = false; _hudDirty = true; } } _highway.SetEnergy(_energy, _spActive); _highway.Update(_t, _chordState, _hitMask, _susNote); if (_t > _endTime) { Finish(); } } private void OnPress(int lane, double t) { Chord[] chords = _chart.Chords; Note[] notes = _chart.Notes; byte b = (byte)(1 << lane); for (int i = _cursor; i < chords.Length; i++) { double num = chords[i].Time - t; if (num > _hitWindow) { break; } if (num < 0.0 - _hitWindow || _chordState[i] != 0 || (chords[i].Mask & b) == 0 || (_hitMask[i] & b) != 0) { continue; } _hitMask[i] |= b; _score += 50 * EffectiveMultiplier; int first = chords[i].First; int num2 = first + chords[i].Count; _susNote[lane] = -1; for (int j = first; j < num2; j++) { if (notes[j].Lane == lane) { if (notes[j].Length > 0.0) { _susNote[lane] = j; } break; } } if (_hitMask[i] == chords[i].Mask) { _chordState[i] = 1; _streak++; _hitChords++; if (_streak > _bestStreak) { _bestStreak = _streak; } int phrase = chords[i].Phrase; if (phrase >= 0 && chords[i].PhraseLast && !_phraseBroken[phrase]) { _energy = Math.Min(1f, _energy + 0.25f); } } _hudDirty = true; return; } if (Plugin.PenalizeExtraPresses.Value) { _streak = 0; _hudDirty = true; } } private void Finish() { //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)_source != (Object)null) { _source.Stop(); } } catch { } int num = _hitChords + _missChords; double num2 = ((num > 0) ? (100.0 * (double)_hitChords / (double)num) : 0.0); _results = _song.Display + " (" + _playLabel + ")\nScore " + _score.ToString("N0") + "\nChords hit " + _hitChords + "/" + num + " (" + num2.ToString("F1") + "%)\nBest streak " + _bestStreak + "\n\n" + ((object)Plugin.MenuKey.Value/*cast due to .constrained prefix*/).ToString() + " to pick another song"; _phase = Phase.Finished; } public void Stop() { _gen++; _loadResult = null; CleanupSong(); _phase = Phase.Idle; _status = ""; _menuDirty = true; } private void CleanupSong() { try { if ((Object)(object)_source != (Object)null) { _source.Stop(); _source.clip = null; } } catch { } if ((Object)(object)_clip != (Object)null) { try { Object.Destroy((Object)(object)_clip); } catch { } _clip = null; } _highway.Hide(); _spActive = false; _energy = 0f; _pcm = null; _chart = null; _chordState = null; _hitMask = null; } public void Shutdown() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown try { Stop(); _highway.Dispose(); if ((Object)(object)_audioGO != (Object)null) { Object.Destroy((Object)(object)_audioGO); } _audioGO = null; _source = null; } catch (Exception ex) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(10, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Shutdown: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogDebug(val); } } private void EnsureStyles() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown if (_label == null) { _label = new GUIStyle(GUI.skin.label); _label.fontSize = Math.Max(14, Screen.height / 45); _label.normal.textColor = Color.white; _box = new GUIStyle(GUI.skin.box); } } public void Draw() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) Event current = Event.current; if (current == null || (int)current.type != 7 || (!_menuOpen && _phase == Phase.Idle)) { return; } EnsureStyles(); if (_menuOpen) { if (_menuDirty) { RebuildMenuText(); _menuDirty = false; } float num = Math.Min((float)Screen.width * 0.6f, 900f); float num2 = Math.Min((float)Screen.height * 0.7f, 620f); GUI.Box(new Rect(24f, 24f, num, num2), "", _box); GUI.Label(new Rect(40f, 36f, num - 32f, num2 - 24f), _menuText, _label); return; } switch (_phase) { case Phase.Loading: case Phase.Uploading: GUI.Label(new Rect(40f, (float)Screen.height * 0.3f, 900f, 60f), _status, _label); break; case Phase.Playing: if (_hudDirty && Time.unscaledTime >= _hudNext) { _hud = _song.Display + " (" + _playLabel + ")\nScore " + _score.ToString("N0") + " x" + EffectiveMultiplier + " Streak " + _streak + " Best " + _bestStreak + (_spActive ? "\nOVERDRIVE!" : ((_energy >= 0.5f) ? ("\nOverdrive ready - press " + ((object)Unsafe.As<KeyCode, KeyCode>(ref _spKey)/*cast due to .constrained prefix*/).ToString()) : "")); _hudDirty = false; _hudNext = Time.unscaledTime + 0.1f; } GUI.Label(new Rect(40f, (float)Screen.height * 0.3f, 1000f, 120f), _hud, _label); if (_t < 0.0) { GUI.Label(new Rect(40f, (float)Screen.height * 0.3f + 90f, 600f, 60f), "Starting in " + Math.Ceiling(0.0 - _t), _label); } break; case Phase.Finished: GUI.Label(new Rect(40f, (float)Screen.height * 0.3f, 1000f, 240f), _results, _label); break; } } } internal sealed class SongInfo { public string Dir; public string ChartPath; public bool IsMidi; public string Name; public string Artist; public string Charter; public double DelaySec; public string Display; public int[] Diff = new int[5] { -2, -2, -2, -2, -2 }; public bool AnyDiff; public bool Supports(GuitarPart i) { int num = Diff[(int)i]; if (num >= 0) { return true; } if (num != -2) { return false; } return !AnyDiff; } } internal static class SongLibrary { public static string LastReport = ""; public static List<SongInfo> Scan(string root) { //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Expected O, but got Unknown List<SongInfo> list = new List<SongInfo>(); int num = 0; int num2 = 0; try { Directory.CreateDirectory(root); Stack<string> stack = new Stack<string>(); stack.Push(root); while (stack.Count > 0) { string text = stack.Pop(); num++; string[] files; try { files = Directory.GetFiles(text); } catch { continue; } string text2 = null; string text3 = null; string text4 = null; string text5 = null; bool flag = false; string[] array = files; foreach (string text6 in array) { string fileName = Path.GetFileName(text6); string text7 = Path.GetExtension(text6).ToLowerInvariant(); if (fileName.Equals("notes.chart", StringComparison.OrdinalIgnoreCase)) { text2 = text6; } else if (fileName.Equals("notes.mid", StringComparison.OrdinalIgnoreCase)) { text3 = text6; } else if (text7 == ".chart") { if (text4 == null) { text4 = text6; } } else if (text7 == ".mid" || text7 == ".midi") { if (text5 == null) { text5 = text6; } } else if (text7 == ".sng") { flag = true; } } string text8 = text2 ?? text4 ?? text3 ?? text5; if (text8 != null) { list.Add(ReadInfo(text, text8, !text8.EndsWith(".chart", StringComparison.OrdinalIgnoreCase))); } else if (flag) { num2++; } try { string[] directories = Directory.GetDirectories(text); foreach (string item in directories) { stack.Push(item); } } catch { } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; bool flag2 = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(25, 1, ref flag2); if (flag2) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Song scan stopped early: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogWarning(val); } list.Sort((SongInfo a, SongInfo b) => string.Compare(a.Display, b.Display, StringComparison.OrdinalIgnoreCase)); LastReport = $"Scanned {num} folders, found {list.Count} songs."; if (num2 > 0) { LastReport += $" {num2} folders hold only .sng files, which are not supported yet (download the folder/zip version)."; } return list; } private static SongInfo ReadInfo(string dir, string chartPath, bool isMidi) { SongInfo songInfo = new SongInfo { Dir = dir, ChartPath = chartPath, IsMidi = isMidi, Name = "", Artist = "", Charter = "" }; try { string path = Path.Combine(dir, "song.ini"); if (File.Exists(path)) { foreach (string item in File.ReadLines(path)) { int num = item.IndexOf('='); if (num <= 0) { continue; } string text = item.Substring(0, num).Trim().ToLowerInvariant(); string text2 = item.Substring(num + 1).Trim(); switch (text) { case "name": songInfo.Name = text2; continue; case "artist": songInfo.Artist = text2; continue; case "charter": songInfo.Charter = text2; continue; case "delay": { if (int.TryParse(text2, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { songInfo.DelaySec = (double)result / 1000.0; } continue; } } if (!text.StartsWith("diff_", StringComparison.Ordinal)) { continue; } songInfo.AnyDiff = true; for (int i = 0; i < Instruments.All.Length; i++) { if (!(text != Instruments.IniKey(Instruments.All[i]))) { if (int.TryParse(text2, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2)) { songInfo.Diff[i] = result2; } break; } } } } } catch { } if (string.IsNullOrEmpty(songInfo.Name)) { songInfo.Name = Path.GetFileName(dir); } songInfo.Display = (string.IsNullOrEmpty(songInfo.Artist) ? songInfo.Name : (songInfo.Artist + " - " + songInfo.Name)); return songInfo; } } } namespace RockHero.World { internal sealed class Highway : IDisposable { private const int PoolSize = 192; private const double BehindSeconds = 0.25; private const float HeadHeight = 0.13f; private const float ZLines = -0.006f; private const float ZStrike = -0.012f; private const float ZFret = -0.018f; private const float ZTail = -0.024f; private const float ZHead = -0.03f; private static readonly Color[] LaneColors = (Color[])(object)new Color[5] { new Color(0.1f, 0.85f, 0.2f, 1f), new Color(0.92f, 0.15f, 0.15f, 1f), new Color(0.96f, 0.86f, 0.1f, 1f), new Color(0.15f, 0.42f, 0.96f, 1f), new Color(0.98f, 0.55f, 0.1f, 1f) }; private GameObject _root; private Transform _board; private Mesh _mesh; private float _width; private float _length; private float _speed; private float _laneW; private float _strike; private float _tilt; private float[] _laneX; private double _ahead; private static readonly Color BgNormal = new Color(0.04f, 0.04f, 0.07f, 1f); private static readonly Color BgOverdrive = new Color(0.04f, 0.16f, 0.26f, 1f); private static readonly Color LineNormal = new Color(0.45f, 0.45f, 0.52f, 1f); private static readonly Color LineOverdrive = new Color(0.55f, 0.88f, 1f, 1f); private static readonly Color MeterIdle = new Color(0.3f, 0.72f, 0.95f, 1f); private static readonly Color MeterActive = new Color(1f, 1f, 1f, 1f); private Material[] _headMat; private Material[] _tailMat; private Material[] _fretMat; private Material _bgMat; private Material _lineMat; private Material _spHeadMat; private Material _spTailMat; private Material _meterFillMat; private Transform _meterFillT; private float _meterX; private float _meterBottom; private float _meterH; private float _energyShown = -1f; private bool _odShown; private Color[] _fretDim; private Color[] _fretBright; private readonly bool[] _fretHeld = new bool[5]; private readonly GameObject[] _headGO = (GameObject[])(object)new GameObject[192]; private readonly GameObject[] _tailGO = (GameObject[])(object)new GameObject[192]; private readonly Transform[] _headT = (Transform[])(object)new Transform[192]; private readonly Transform[] _tailT = (Transform[])(object)new Transform[192]; private readonly MeshRenderer[] _headMR = (MeshRenderer[])(object)new MeshRenderer[192]; private readonly MeshRenderer[] _tailMR = (MeshRenderer[])(object)new MeshRenderer[192]; private readonly int[] _slotNote = new int[192]; private readonly int[] _slotStamp = new int[192]; private readonly bool[] _slotUsed = new bool[192]; private readonly bool[] _headOn = new bool[192]; private readonly bool[] _tailOn = new bool[192]; private Chart _chart; private int _first; private int _frame; public void Place(Vector3 groundPos, float yaw) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_root == (Object)null || ConfigChanged()) { Dispose(); Build(); } _root.transform.position = groundPos; _root.transform.rotation = Quaternion.Euler(0f, yaw, 0f); _root.SetActive(true); } public void Hide() { if ((Object)(object)_root != (Object)null) { _root.SetActive(false); } _chart = null; } public void SetChart(Chart chart) { _chart = chart; _first = 0; for (int i = 0; i < 192; i++) { DeactivateSlot(i); } for (int j = 0; j < 5; j++) { SetFretHeld(j, held: false, force: true); } _energyShown = -1f; _odShown = true; SetEnergy(0f, active: false); } private bool ConfigChanged() { return !Mathf.Approximately(_width, Plugin.HighwayWidth.Value) || !Mathf.Approximately(_length, Plugin.HighwayLength.Value) || !Mathf.Approximately(_speed, Plugin.HighwaySpeed.Value) || !Mathf.Approximately(_strike, Plugin.StrikeHeight.Value) || !Mathf.Approximately(_tilt, Plugin.TiltDegrees.Value); } private void Build() { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_0357: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_0435: Unknown result type (might be due to invalid IL or missing references) //IL_045a: Unknown result type (might be due to invalid IL or missing references) //IL_04be: Unknown result type (might be due to invalid IL or missing references) //IL_050f: Unknown result type (might be due to invalid IL or missing references) //IL_0593: Unknown result type (might be due to invalid IL or missing references) //IL_0641: Unknown result type (might be due to invalid IL or missing references) //IL_0706: Unknown result type (might be due to invalid IL or missing references) //IL_070d: Expected O, but got Unknown _width = Plugin.HighwayWidth.Value; _length = Plugin.HighwayLength.Value; _speed = Plugin.HighwaySpeed.Value; _strike = Plugin.StrikeHeight.Value; _tilt = Plugin.TiltDegrees.Value; _laneW = _width / 5f; _ahead = _length / _speed; _laneX = new float[5]; for (int i = 0; i < 5; i++) { _laneX[i] = (float)(i - 2) * _laneW; } _root = new GameObject("RockHero.Highway"); Object.DontDestroyOnLoad((Object)(object)_root); GameObject val = new GameObject("Board"); _board = val.transform; _board.SetParent(_root.transform, false); _board.localPosition = new Vector3(0f, _strike, 0f); _board.localRotation = Quaternion.Euler(_tilt, 0f, 0f); _mesh = Primitives.MakeUnitQuadMesh(); float num = 0.35f; float sy = _length + num; float y = (_length - num) * 0.5f; _bgMat = Primitives.MakeMaterial(BgNormal, 0); MeshRenderer renderer; GameObject val2 = Primitives.MakeRenderer("BG", _mesh, _bgMat, _board, out renderer); Set(val2.transform, 0f, y, 0f, _width + 0.12f, sy); _lineMat = Primitives.MakeMaterial(LineNormal, 1); for (int j = 0; j <= 5; j++) { GameObject val3 = Primitives.MakeRenderer("Line" + j, _mesh, _lineMat, _board, out renderer); Set(val3.transform, ((float)j - 2.5f) * _laneW, y, -0.006f, 0.012f, sy); } GameObject val4 = Primitives.MakeRenderer("Strike", _mesh, Primitives.MakeMaterial(new Color(0.92f, 0.92f, 0.95f, 1f), 2), _board, out renderer); Set(val4.transform, 0f, 0f, -0.012f, _width, 0.025f); _headMat = (Material[])(object)new Material[5]; _tailMat = (Material[])(object)new Material[5]; _fretMat = (Material[])(object)new Material[5]; _fretDim = (Color[])(object)new Color[5]; _fretBright = (Color[])(object)new Color[5]; for (int k = 0; k < 5; k++) { Color val5 = LaneColors[k]; _headMat[k] = Primitives.MakeMaterial(val5, 5); _tailMat[k] = Primitives.MakeMaterial(new Color(val5.r * 0.75f, val5.g * 0.75f, val5.b * 0.75f, 1f), 4); _fretDim[k] = new Color(val5.r * 0.3f, val5.g * 0.3f, val5.b * 0.3f, 1f); _fretBright[k] = val5; _fretMat[k] = Primitives.MakeMaterial(_fretDim[k], 3); GameObject val6 = Primitives.MakeRenderer("Fret" + k, _mesh, _fretMat[k], _board, out renderer); Set(val6.transform, _laneX[k], 0f, -0.018f, _laneW * 0.82f, 0.13f); } _spHeadMat = Primitives.MakeMaterial(new Color(0.88f, 0.96f, 1f, 1f), 5); _spTailMat = Primitives.MakeMaterial(new Color(0.45f, 0.75f, 0.95f, 1f), 4); _meterX = _width * 0.5f + 0.16f; _meterBottom = 0f; _meterH = _length * 0.5f; GameObject val7 = Primitives.MakeRenderer("MeterBG", _mesh, Primitives.MakeMaterial(new Color(0.1f, 0.1f, 0.14f, 1f), 1), _board, out renderer); Set(val7.transform, _meterX, _meterBottom + _meterH * 0.5f, -0.006f, 0.07f, _meterH); _meterFillMat = Primitives.MakeMaterial(MeterIdle, 2); GameObject val8 = Primitives.MakeRenderer("MeterFill", _mesh, _meterFillMat, _board, out renderer); Set(val8.transform, _meterX, _meterBottom, -0.012f, 0.05f, 0.0001f); _meterFillT = val8.transform; GameObject val9 = Primitives.MakeRenderer("MeterHalf", _mesh, Primitives.MakeMaterial(new Color(0.9f, 0.9f, 0.95f, 1f), 3), _board, out renderer); Set(val9.transform, _meterX, _meterBottom + _meterH * 0.5f, -0.018f, 0.11f, 0.012f); for (int l = 0; l < 192; l++) { GameObject val10 = Primitives.MakeRenderer("H" + l, _mesh, _headMat[0], _board, out _headMR[l]); val10.transform.localScale = new Vector3(_laneW * 0.8f, 0.13f, 1f); val10.SetActive(false); _headGO[l] = val10; _headT[l] = val10.transform; GameObject val11 = Primitives.MakeRenderer("T" + l, _mesh, _tailMat[0], _board, out _tailMR[l]); val11.SetActive(false); _tailGO[l] = val11; _tailT[l] = val11.transform; _slotNote[l] = -1; _slotStamp[l] = -1; } ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val12 = new BepInExInfoLogInterpolatedStringHandler(51, 4, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val12).AppendLiteral("Highway built: "); ((BepInExLogInterpolatedStringHandler)val12).AppendFormatted<float>(_width, "F1"); ((BepInExLogInterpolatedStringHandler)val12).AppendLiteral("m wide, "); ((BepInExLogInterpolatedStringHandler)val12).AppendFormatted<float>(_length, "F1"); ((BepInExLogInterpolatedStringHandler)val12).AppendLiteral("m long, "); ((BepInExLogInterpolatedStringHandler)val12).AppendFormatted<double>(_ahead, "F2"); ((BepInExLogInterpolatedStringHandler)val12).AppendLiteral("s look-ahead, pool "); ((BepInExLogInterpolatedStringHandler)val12).AppendFormatted<int>(192); ((BepInExLogInterpolatedStringHandler)val12).AppendLiteral("."); } log.LogInfo(val12); } private static void Set(Transform t, float x, float y, float z, float sx, float sy) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) t.localPosition = new Vector3(x, y, z); t.localScale = new Vector3(sx, sy, 1f); } public void SetFretHeld(int lane, bool held, bool force = false) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) if (_fretMat != null && (force || _fretHeld[lane] != held)) { _fretHeld[lane] = held; Primitives.SetTint(_fretMat[lane], held ? _fretBright[lane] : _fretDim[lane]); } } public void SetEnergy(float energy, bool active) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_meterFillT == (Object)null)) { if (active != _odShown) { _odShown = active; Primitives.SetTint(_bgMat, active ? BgOverdrive : BgNormal); Primitives.SetTint(_lineMat, active ? LineOverdrive : LineNormal); Primitives.SetTint(_meterFillMat, active ? MeterActive : MeterIdle); } if (Mathf.Abs(energy - _energyShown) > 0.003f || (energy <= 0f && _energyShown > 0f)) { _energyShown = energy; float num = Mathf.Max(0.0001f, _meterH * energy); _meterFillT.localPosition = new Vector3(_meterX, _meterBottom + num * 0.5f, -0.012f); _meterFillT.localScale = new Vector3(0.05f, num, 1f); } } } public void Update(double t, byte[] chordState, byte[] hitMask, int[] susNote) { //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) if (_chart == null || (Object)(object)_root == (Object)null) { return; } Note[] notes = _chart.Notes; _frame++; while (_first < notes.Length && notes[_first].Time + notes[_first].Length < t - 0.25) { _first++; } int num = Math.Min(notes.Length, _first + 192); for (int i = _first; i < num; i++) { ref Note reference = ref notes[i]; double num2 = reference.Time - t; if (num2 > _ahead) { break; } int num3 = i % 192; if (_slotNote[num3] != i) { Configure(num3, i, reference.Lane, reference.Star); } _slotStamp[num3] = _frame; _slotUsed[num3] = true; float num4 = (float)(num2 * (double)_speed); bool flag = (hitMask[reference.Chord] & (1 << (int)reference.Lane)) != 0; bool flag2 = !flag && num2 >= -0.25; SetOn(_headGO[num3], _headOn, num3, flag2); if (flag2) { _headT[num3].localPosition = new Vector3(_laneX[reference.Lane], num4, -0.03f); } if (reference.Length > 0.0) { float num5 = ((flag && num4 < 0f) ? 0f : num4); float num6 = num4 + (float)(reference.Length * (double)_speed); if (num6 > _length) { num6 = _length; } float num7 = num6 - num5; bool flag3 = num7 > 0.01f && num5 < _length && (!flag || susNote[reference.Lane] == i); SetOn(_tailGO[num3], _tailOn, num3, flag3); if (flag3) { Transform val = _tailT[num3]; val.localPosition = new Vector3(_laneX[reference.Lane], num5 + num7 * 0.5f, -0.024f); val.localScale = new Vector3(_laneW * 0.22f, num7, 1f); } } } for (int j = 0; j < 192; j++) { if (_slotUsed[j] && _slotStamp[j] != _frame) { DeactivateSlot(j); } } } private void Configure(int s, int noteIndex, byte lane, bool star) { ((Renderer)_headMR[s]).sharedMaterial = (star ? _spHeadMat : _headMat[lane]); ((Renderer)_tailMR[s]).sharedMaterial = (star ? _spTailMat : _tailMat[lane]); _slotNote[s] = noteIndex; _headOn[s] = false; _tailOn[s] = false; _headGO[s].SetActive(false); _tailGO[s].SetActive(false); } private void DeactivateSlot(int s) { if ((Object)(object)_headGO[s] == (Object)null) { _slotNote[s] = -1; _slotUsed[s] = false; return; } if (_headOn[s]) { _headGO[s].SetActive(false); _headOn[s] = false; } if (_tailOn[s]) { _tailGO[s].SetActive(false); _tailOn[s] = false; } _slotUsed[s] = false; _slotNote[s] = -1; } private static void SetOn(GameObject go, bool[] state, int s, bool on) { if (state[s] != on) { state[s] = on; go.SetActive(on); } } public void Dispose() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown try { if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)_root); } if ((Object)(object)_mesh != (Object)null) { Object.Destroy((Object)(object)_mesh); } } catch (Exception ex) { ManualLogSource log = Plugin.Log; bool flag = default(bool); BepInExDebugLogInterpolatedStringHandler val = new BepInExDebugLogInterpolatedStringHandler(17, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Highway dispose: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogDebug(val); } _root = null; _board = null; _mesh = null; _meterFillT = null; _bgMat = null; _lineMat = null; _meterFillMat = null; _spHeadMat = null; _spTailMat = null; _energyShown = -1f; _chart = null; for (int i = 0; i < 192; i++) { _headGO[i] = null; _tailGO[i] = null; _headT[i] = null; _tailT[i] = null; _headMR[i] = null; _tailMR[i] = null; _headOn[i] = false; _tailOn[i] = false; _slotUsed[i] = false; _slotNote[i] = -1; _slotStamp[i] = -1; } } } internal static class Primitives { private static readonly string[] ShaderCandidates = new string[8] { "Universal Render Pipeline/Unlit", "Unlit/Texture", "Unlit/Color", "Sprites/Default", "UI/Default", "Universal Render Pipeline/Lit", "Standard", "Legacy Shaders/Diffuse" }; private static Shader _cachedShader; private static Material _cachedSceneTemplate; public static Mesh MakeUnitQuadMesh() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown Vector3[] array = (Vector3[])(object)new Vector3[4] { new Vector3(-0.5f, -0.5f, 0f), new Vector3(0.5f, -0.5f, 0f), new Vector3(0.5f, 0.5f, 0f), new Vector3(-0.5f, 0.5f, 0f) }; Vector2[] array2 = (Vector2[])(object)new Vector2[4] { new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(0f, 1f) }; Vector3[] array3 = (Vector3[])(object)new Vector3[4] { -Vector3.forward, -Vector3.forward, -Vector3.forward, -Vector3.forward }; int[] array4 = new int[6] { 0, 2, 1, 0, 3, 2 }; Mesh val = new Mesh(); ((Object)val).name = "RockHero.UnitQuad"; val.vertices = Il2CppStructArray<Vector3>.op_Implicit(array); val.uv = Il2CppStructArray<Vector2>.op_Implicit(array2); val.normals = Il2CppStructArray<Vector3>.op_Implicit(array3); val.triangles = Il2CppStructArray<int>.op_Implicit(array4); val.RecalculateBounds(); return val; } public static GameObject MakeRenderer(string name, Mesh mesh, Material mat, Transform parent, out MeshRenderer renderer) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown GameObject val = new GameObject(name); val.transform.SetParent(parent, false); val.AddComponent<MeshFilter>().sharedMesh = mesh; renderer = val.AddComponent<MeshRenderer>(); ((Renderer)renderer).sharedMaterial = mat; ((Renderer)renderer).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)renderer).receiveShadows = false; return val; } public static Material MakeMaterial(Color tint, int drawOrder) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Expected O, but got Unknown //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown bool flag = default(bool); if ((Object)(object)_cachedShader == (Object)null) { string[] shaderCandidates = ShaderCandidates; foreach (string text in shaderCandidates) { try { Shader val = Shader.Find(text); if ((Object)(object)val != (Object)null) { _cachedShader = val; ManualLogSource log = Plugin.Log; BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(16, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Highway shader: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text); } log.LogInfo(val2); break; } } catch { } } } Material val3; if ((Object)(object)_cachedShader != (Object)null) { val3 = new Material(_cachedShader); } else { if ((Object)(object)_cachedSceneTemplate == (Object)null) { try { Il2CppArrayBase<MeshRenderer> val4 = Object.FindObjectsOfType<MeshRenderer>(); foreach (MeshRenderer item in val4) { Material val5 = (((Object)(object)item != (Object)null) ? ((Renderer)item).sharedMaterial : null); if ((Object)(object)val5 != (Object)null && (Object)(object)val5.shader != (Object)null) { _cachedSceneTemplate = val5; break; } } } catch { } } if ((Object)(object)_cachedSceneTemplate == (Object)null) { throw new InvalidOperationException("No usable shader found in this build."); } val3 = new Material(_cachedSceneTemplate); ManualLogSource log2 = Plugin.Log; BepInExWarningLogInterpolatedStringHandler val6 = new BepInExWarningLogInterpolatedStringHandler(48, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val6).AppendLiteral("No known shader found; cloned scene material '"); ((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<string>(((Object)_cachedSceneTemplate).name); ((BepInExLogInterpolatedStringHandler)val6).AppendLiteral("'."); } log2.LogWarning(val6); } ((Object)val3).name = "RockHero.Mat"; SetTint(val3, tint); val3.renderQueue = 3000 + drawOrder; return val3; } public static void SetTint(Material mat, Color tint) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)mat == (Object)null)) { if (mat.HasProperty("_Color")) { mat.SetColor("_Color", tint); } if (mat.HasProperty("_BaseColor")) { mat.SetColor("_BaseColor", tint); } } } } } namespace RockHero.Charts { internal static class ChartFileParser { private static readonly char[] Space = new char[2] { ' ', '\t' }; public static Chart Load(string path, GuitarPart instrument, string difficulty, double delaySec, out string error) { error = null; string text = Instruments.ChartSuffix(instrument); try { int result = 192; List<KeyValuePair<long, double>> list = new List<KeyValuePair<long, double>>(); Dictionary<string, List<RawNote>> dictionary = new Dictionary<string, List<RawNote>>(StringComparer.OrdinalIgnoreCase); Dictionary<string, List<KeyValuePair<long, long>>> dictionary2 = new Dictionary<string, List<KeyValuePair<long, long>>>(StringComparer.OrdinalIgnoreCase); List<RawNote> list2 = null; List<KeyValuePair<long, long>> list3 = null; string text2 = null; foreach (string item in File.ReadLines(path)) { string text3 = item.Trim(); if (text3.Length == 0 || text3[0] == '{' || text3[0] == '}') { continue; } if (text3[0] == '[') { text2 = text3.Trim('[', ']', ' '); list2 = null; list3 = null; if (IsInstrumentSection(text2, text)) { list2 = new List<RawNote>(1024); list3 = new List<KeyValuePair<long, long>>(); dictionary[text2] = list2; dictionary2[text2] = list3; } continue; } int num = text3.IndexOf('='); if (num <= 0) { continue; } string text4 = text3.Substring(0, num).Trim(); string text5 = text3.Substring(num + 1).Trim(); if (text2 == null) { continue; } long result4; if (text2.Equals("Song", StringComparison.OrdinalIgnoreCase)) { if (text4.Equals("Resolution", StringComparison.OrdinalIgnoreCase)) { int.TryParse(text5, NumberStyles.Integer, CultureInfo.InvariantCulture, out result); } } else if (text2.Equals("SyncTrack", StringComparison.OrdinalIgnoreCase)) { if (long.TryParse(text4, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2)) { string[] array = text5.Split(Space, StringSplitOptions.RemoveEmptyEntries); if (array.Length >= 2 && array[0] == "B" && long.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result3) && result3 > 0) { list.Add(new KeyValuePair<long, double>(result2, 60000000000.0 / (double)result3)); } } } else if (list2 != null && long.TryParse(text4, NumberStyles.Integer, CultureInfo.InvariantCulture, out result4)) { string[] array2 = text5.Split(Space, StringSplitOptions.RemoveEmptyEntries); int result6; if (array2.Length >= 3 && array2[0] == "S" && array2[1] == "2") { long.TryParse(array2[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result5); list3.Add(new KeyValuePair<long, long>(result4, result4 + Math.Max(1L, result5))); } else if (array2.Length >= 3 && !(array2[0] != "N") && int.TryParse(array2[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out result6) && result6 >= 0 && result6 <= 4) { long.TryParse(array2[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result7); list2.Add(new RawNote { Start = result4, End = result4 + result7, Lane = (byte)result6 }); } } } if (result <= 0) { result = 192; } TempoMap map = new TempoMap(result, list); for (int i = ChartBuilder.StartIndex(difficulty); i < ChartBuilder.Difficulties.Length; i++) { string key = ChartBuilder.Difficulties[i] + text; if (dictionary.TryGetValue(key, out var value) && value.Count > 0) { dictionary2.TryGetValue(key, out var value2); return ChartBuilder.Build(value, map, result, delaySec, value2); } } error = "No " + Instruments.Label(instrument) + " notes found in this chart."; return null; } catch (Exception ex) { error = "Chart parse failed: " + ex.Message; return null; } } private static bool IsInstrumentSection(string s, string suffix) { for (int i = 0; i < ChartBuilder.Difficulties.Length; i++) { if (s.Equals(ChartBuilder.Difficulties[i] + suffix, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } } internal enum GuitarPart { Guitar, Bass, Rhythm, Coop, Keys } internal static class Instruments { public static readonly GuitarPart[] All = new GuitarPart[5] { GuitarPart.Guitar, GuitarPart.Bass, GuitarPart.Rhythm, GuitarPart.Coop, GuitarPart.Keys }; public static string Label(GuitarPart i) { return i switch { GuitarPart.Bass => "Bass", GuitarPart.Rhythm => "Rhythm Guitar", GuitarPart.Coop => "Co-op Guitar", GuitarPart.Keys => "Keys", _ => "Lead Guitar", }; } public static string ChartSuffix(GuitarPart i) { return i switch { GuitarPart.Bass => "DoubleBass", GuitarPart.Rhythm => "DoubleRhythm", GuitarPart.Coop => "DoubleGuitar", GuitarPart.Keys => "Keyboard", _ => "Single", }; } public static bool MidiTrackMatches(GuitarPart i, string name) { return i switch { GuitarPart.Bass => name.Equals("PART BASS", StringComparison.OrdinalIgnoreCase), GuitarPart.Rhythm => name.Equals("PART RHYTHM", StringComparison.OrdinalIgnoreCase), GuitarPart.Coop => name.Equals("PART GUITAR COOP", StringComparison.OrdinalIgnoreCase), GuitarPart.Keys => name.Equals("PART KEYS", StringComparison.OrdinalIgnoreCase), _ => name.Equals("PART GUITAR", StringComparison.OrdinalIgnoreCase) || name.Equals("T1 GEMS", StringComparison.OrdinalIgnoreCase), }; } public static string IniKey(GuitarPart i) { return i switch { GuitarPart.Bass => "diff_bass", GuitarPart.Rhythm => "diff_rhythm", GuitarPart.Coop => "diff_guitar_coop", GuitarPart.Keys => "diff_keys", _ => "diff_guitar", }; } public static GuitarPart Parse(string s) { GuitarPart[] all = All; for (int i = 0; i < all.Length; i++) { GuitarPart result = all[i]; if (string.Equals(result.ToString(), s, StringComparison.OrdinalIgnoreCase)) { return result; } } return GuitarPart.Guitar; } public static GuitarPart Next(GuitarPart i, int dir) { int num = All.Length; return All[(int)(i + dir % num + num) % num]; } } internal struct Note { public double Time; public double Length; public int Chord; public byte Lane; public bool Star; } internal struct Chord { public double Time; public int First; public int Count; public byte Mask; public int Phrase; public bool PhraseLast; } internal sealed class Chart { public Note[] Notes; public Chord[] Chords; public double LastTime; public int PhraseCount; } internal struct RawNote { public long Start; public long End; public byte Lane; } internal sealed class TempoMap { private readonly long[] _tick; private readonly double[] _sec; private readonly double[] _usPerBeat; private readonly double _res; public TempoMap(int resolution, List<KeyValuePair<long, double>> changes) { _res = ((resolution > 0) ? resolution : 192); changes.Sort((KeyValuePair<long, double> a, KeyValuePair<long, double> b) => a.Key.CompareTo(b.Key)); List<long> list = new List<long>(); List<double> list2 = new List<double>(); foreach (KeyValuePair<long, double> change in changes) { if (!(change.Value <= 0.0)) { if (list.Count == 0 && change.Key > 0) { list.Add(0L); list2.Add(change.Value); } if (list.Count > 0 && list[list.Count - 1] == change.Key) { list2[list2.Count - 1] = change.Value; continue; } list.Add(change.Key); list2.Add(change.Value); } } if (list.Count == 0) { list.Add(0L); list2.Add(500000.0); } _tick = list.ToArray(); _usPerBeat = list2.ToArray(); _sec = new double[_tick.Length]; for (int num = 1; num < _tick.Length; num++) { _sec[num] = _sec[num - 1] + (double)(_tick[num] - _tick[num - 1]) * _usPerBeat[num - 1] / (_res * 1000000.0); } } public double TickToSeconds(long tick) { int num = Array.BinarySearch(_tick, tick); if (num < 0) { num = ~num - 1; } if (num < 0) { num = 0; } return _sec[num] + (double)(tick - _tick[num]) * _usPerBeat[num] / (_res * 1000000.0); } } internal static class ChartBuilder { public static readonly string[] Difficulties = new string[4] { "Expert", "Hard", "Medium", "Easy" }; public static int StartIndex(string difficulty) { for (int i = 0; i < Difficulties.Length; i++) { if (string.Equals(Difficulties[i], difficulty, StringComparison.OrdinalIgnoreCase)) { return i; } } return 0; } public static Chart Build(List<RawNote> raw, TempoMap map, int resolution, double offsetSec, List<KeyValuePair<long, long>> phrases) { if (raw.Count == 0) { return null; } if (phrases == null) { phrases = new List<KeyValuePair<long, long>>(); } phrases.Sort((KeyValuePair<long, long> a, KeyValuePair<long, long> keyValuePair) => a.Key.CompareTo(keyValuePair.Key)); int num = 0; raw.Sort(delegate(RawNote a, RawNote rawNote2) { int num14 = a.Start.CompareTo(rawNote2.Start); return (num14 != 0) ? num14 : a.Lane.CompareTo(rawNote2.Lane); }); Note[] array = new Note[raw.Count]; Chord[] array2 = new Chord[raw.Count]; int num2 = 0; int num3 = 0; long num4 = -1L; byte b = byte.MaxValue; long num5 = Math.Max(1, resolution / 3); double num6 = 0.0; for (int num7 = 0; num7 < raw.Count; num7++) { RawNote rawNote = raw[num7]; if (rawNote.Start == num4 && rawNote.Lane == b) { continue; } double num8 = map.TickToSeconds(rawNote.Start) + offsetSec; double num9 = 0.0; if (rawNote.End - rawNote.Start > num5) { num9 = map.TickToSeconds(rawNote.End) - map.TickToSeconds(rawNote.Start); } if (rawNote.Start != num4) { for (; num < phrases.Count && phrases[num].Value <= rawNote.Start; num++) { } int phrase = ((num < phrases.Count && rawNote.Start >= phrases[num].Key) ? num : (-1)); array2[num3] = new Chord { Time = num8, First = num2, Count = 0, Mask = 0, Phrase = phrase, PhraseLast = false }; num3++; } int num10 = num3 - 1; array2[num10].Count++; array2[num10].Mask |= (byte)(1 << (int)rawNote.Lane); array[num2++] = new Note { Time = num8, Length = num9, Chord = num10, Lane = rawNote.Lane, Star = (array2[num10].Phrase >= 0) }; if (num8 + num9 > num6) { num6 = num8 + num9; } num4 = rawNote.Start; b = rawNote.Lane; } Array.Resize(ref array, num2); Array.Resize(ref array2, num3); int[] array3 = new int[phrases.Count]; for (int num11 = 0; num11 < array3.Length; num11++) { array3[num11] = -1; } for (int num12 = 0; num12 < num3; num12++) { if (array2[num12].Phrase >= 0) { array3[array2[num12].Phrase] = num12; } } for (int num13 = 0; num13 < array3.Length; num13++) { if (array3[num13] >= 0) { array2[array3[num13]].PhraseLast = true; } } return new Chart { Notes = array, Chords = array2, LastTime = num6, PhraseCount = phrases.Count }; } } internal static class MidiFileParser { private struct MidiEvent { public long Tick; public byte Note; public bool On; } private static readonly int[] Bases = new int[4] { 96, 84, 72, 60 }; public static Chart Load(string path, GuitarPart instrument, string difficulty, double delaySec, out string error) { error = null; try { byte[] array = File.ReadAllBytes(path); if (array.Length < 14 || array[0] != 77 || array[1] != 84 || array[2] != 104 || array[3] != 100) { error = "Not a MIDI file."; return null; } int num = ReadInt32(array, 4); int num2 = (array[10] << 8) | array[11]; int num3 = (array[12] << 8) | array[13]; if ((num3 & 0x8000) != 0 || num3 == 0) { error = "SMPTE-timed MIDI is not supported."; return null; } int num4 = 8 + num; List<KeyValuePair<long, double>> list = new List<KeyValuePair<long, double>>(); List<MidiEvent> list2 = new List<MidiEvent>(); for (int i = 0; i < num2; i++) { if (num4 + 8 > array.Length) { break; } int num5 = ReadInt32(array, num4 + 4); int num6 = num4 + 8; int end = Math.Min(array.Length, num6 + num5); if (array[num4] == 77 && array[num4 + 1] == 84 && array[num4 + 2] == 114 && array[num4 + 3] == 107) { List<MidiEvent> list3 = new List<MidiEvent>(2048); if (ParseTrack(array, num6, end, list, list3, instrument) && list2.Count == 0) { list2 = list3; } } num4 = num6 + num5; } TempoMap map = new TempoMap(num3, list); for (int j = ChartBuilder.StartIndex(difficulty); j < Bases.Length; j++) { List<RawNote> list4 = Pair(list2, Bases[j]); if (list4.Count > 0) { return ChartBuilder.Build(list4, map, num3, delaySec, PairPhrases(list2)); } } error = "No " + Instruments.Label(instrument) + " notes found in this chart."; return null; } catch (Exception ex) { error = "MIDI parse failed: " + ex.Message; return null; } } private static List<KeyValuePair<long, long>> PairPhrases(List<MidiEvent> events) { List<KeyValuePair<long, long>> list = new List<KeyValuePair<long, long>>(); long num = -1L; for (int i = 0; i < events.Count; i++) { MidiEvent midiEvent = events[i]; if (midiEvent.Note != 116) { continue; } if (midiEvent.On) { if (num < 0) { num = midiEvent.Tick; } } else if (num >= 0) { list.Add(new KeyValuePair<long, long>(num, Math.Max(midiEvent.Tick, num + 1))); num = -1L; } } return list; } private static List<RawNote> Pair(List<MidiEvent> events, int noteBase) { List<RawNote> list = new List<RawNote>(1024); long[] array = new long[128]; Array.Fill(array, -1L); for (int i = 0; i < events.Count; i++) { MidiEvent midiEvent = events[i]; int num = midiEvent.Note - noteBase; if (num < 0 || num > 4) { continue; } if (midiEvent.On) { if (array[midiEvent.Note] < 0) { array[midiEvent.Note] = midiEvent.Tick; } } else if (array[midiEvent.Note] >= 0) { list.Add(new RawNote { Start = array[midiEvent.Note], End = midiEvent.Tick, Lane = (byte)num }); array[midiEvent.Note] = -1L; } } return list; } private static bool ParseTrack(byte[] d, int p, int end, List<KeyValuePair<long, double>> tempos, List<MidiEvent> notes, GuitarPart instrument) { long num = 0L; byte b = 0; bool flag = false; while (p < end) { num += ReadVlq(d, ref p); if (p >= end) { break; } byte b2 = d[p]; if (b2 == byte.MaxValue) { p++; byte b3 = d[p++]; int num2 = ReadVlq(d, ref p); if (b3 == 81 && num2 == 3) { int num3 = (d[p] << 16) | (d[p + 1] << 8) | d[p + 2]; tempos.Add(new KeyValuePair<long, double>(num, num3)); } else if (b3 == 3) { string name = Encoding.UTF8.GetString(d, p, num2).Trim(); flag = Instruments.MidiTrackMatches(instrument, name); } p += num2; if (b3 == 47) { break; } } else if (b2 == 240 || b2 == 247) { p++; int num4 = ReadVlq(d, ref p); p += num4; } else { if (b2 >= 128) { b = b2; p++; } int num5 = b & 0xF0; int num6 = d[p++]; int num7 = ((num5 != 192 && num5 != 208) ? d[p++] : 0); if (flag && (num5 == 144 || num5 == 128)) { notes.Add(new MidiEvent { Tick = num, Note = (byte)num6, On = (num5 == 144 && num7 > 0) }); } } } return flag; } private static int ReadVlq(byte[] d, ref int p) { int num = 0; byte b; do { b = d[p++]; num = (num << 7) | (b & 0x7F); } while ((b & 0x80) != 0); return num; } private static int ReadInt32(byte[] d, int p) { return (d[p] << 24) | (d[p + 1] << 16) | (d[p + 2] << 8) | d[p + 3]; } } }