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(".NETFramework,Version=v4.5.2", FrameworkDisplayName = ".NET Framework 4.5.2")] [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 in_data, Span out_pcm, int frame_size, bool decode_fec = false); int Decode(ReadOnlySpan in_data, Span 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 in_pcm, int frame_size, Span out_data, int max_data_bytes); int Encode(ReadOnlySpan in_pcm, int frame_size, Span 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 data, Span out_pcm, int frame_size, bool decode_fec); int DecodeMultistream(ReadOnlySpan data, Span 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 in_pcm, int frame_size, Span out_data, int max_data_bytes); int EncodeMultistream(ReadOnlySpan in_pcm, int frame_size, Span 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 input, ref int in_len, Span output, ref int out_len); void Process(int channel_index, Span input, ref int in_len, Span output, ref int out_len); void ProcessInterleaved(Span input, ref int in_len, Span output, ref int out_len); void ProcessInterleaved(Span input, ref int in_len, Span 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 = (float)Math.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) ? (-(float)Math.PI / 2f) : ((float)Math.PI / 2f)); } if (!(y < 0f)) { return (float)Math.PI / 2f; } return -(float)Math.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) ? (-(float)Math.PI / 2f) : ((float)Math.PI / 2f)) - ((x * y < 0f) ? (-(float)Math.PI / 2f) : ((float)Math.PI / 2f)); } return ((y < 0f) ? (-(float)Math.PI / 2f) : ((float)Math.PI / 2f)) - ((x * y < 0f) ? (-(float)Math.PI / 2f) : ((float)Math.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(TonalityAnalysisState tonal, CeltMode celt_mode, ReadOnlySpan x, int len, int offset, int c1, int c2, int C, int lsb_depth, Downmix.downmix_func 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 * (float)Math.PI) * fast_atan2f(y, x2); float num13 = num12 - angle[i]; float num14 = num13 - d_angle[i]; float num15 = 1f / (2f * (float)Math.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(TonalityAnalysisState analysis, CeltMode celt_mode, ReadOnlySpan analysis_pcm, int analysis_frame_size, int frame_size, int c1, int c2, int C, int Fs, int lsb_depth, Downmix.downmix_func 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 input, int input_ptr, int cutoff_Hz, Span 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 input, int input_ptr, int cutoff_Hz, Span 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 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(24, 16); int[][] array2 = Arrays.InitTwoDimensionalArray(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(ReadOnlySpan x, int len, int C, int Fs, int bitrate, int tonality, float[] mem, int buffering, Downmix.downmix_func 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(ReadOnlySpan analysis_pcm, int frame_size, OpusFramesize variable_duration, int C, int Fs, int bitrate_bps, int delay_compensation, Downmix.downmix_func 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 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 in1, int in1_ptr, Span in2, int in2_ptr, Span 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(ReadOnlySpan _x, Span sub, int sub_ptr, int subframe, int offset, int c1, int c2, int C); internal static void downmix_float(ReadOnlySpan x, Span 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 x, Span 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 _out, Pointer _ps, Pointer _bands, int _nbands, Pointer _in, int _nchannels, int _nframes, int _window_sz, int _step, int _downsample) { Pointer pointer = Concentus.Common.CPlusPlus.Pointer.Malloc((3 + _nchannels) * _window_sz); Pointer pointer2 = pointer.Point(_window_sz); Pointer pointer3 = pointer2.Point(_window_sz); Pointer 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 pointer = Concentus.Common.CPlusPlus.Pointer.Malloc(num6 * 21 * nchannels); Pointer pointer2 = Concentus.Common.CPlusPlus.Pointer.Malloc(num6 * 240 * nchannels); Pointer pointer3 = Concentus.Common.CPlusPlus.Pointer.Malloc(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 * (float)Math.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 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 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 encodedData, Span 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 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 frameData, int lostFlag, int newPacketFlag, EntropyCoder psRangeDec, Span 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 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(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 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 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 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_interpolation_factor_iCDF, 8u); } else { psDec.indices.NLSFInterpCoef_Q2 = 4; } if (psDec.indices.signalType == 2) { int num2 = 1; if (condCoding == 2 && psDec.ec_prevSignalType == 2) { int num3 = (short)psRangeDec.dec_icdf(frameData, Tables.silk_pitch_delta_iCDF, 8u); if (num3 > 0) { num3 -= 9; psDec.indices.lagIndex = (short)(psDec.ec_prevLagIndex + num3); num2 = 0; } } if (num2 != 0) { psDec.indices.lagIndex = (short)(psRangeDec.dec_icdf(frameData, Tables.silk_pitch_lag_iCDF, 8u) * Inlines.silk_RSHIFT(psDec.fs_kHz, 1)); psDec.indices.lagIndex += (short)psRangeDec.dec_icdf(frameData, psDec.pitch_lag_low_bits_iCDF, 8u); } psDec.ec_prevLagIndex = psDec.indices.lagIndex; psDec.indices.contourIndex = (sbyte)psRangeDec.dec_icdf(frameData, psDec.pitch_contour_iCDF, 8u); psDec.indices.PERIndex = (sbyte)psRangeDec.dec_icdf(frameData, Tables.silk_LTP_per_index_iCDF, 8u); for (int j = 0; j < psDec.nb_subfr; j++) { psDec.indices.LTPIndex[j] = (sbyte)psRangeDec.dec_icdf(frameData, Tables.silk_LTP_gain_iCDF_ptrs[psDec.indices.PERIndex], 8u); } if (condCoding == 0) { psDec.indices.LTP_scaleIndex = (sbyte)psRangeDec.dec_icdf(frameData, Tables.silk_LTPscale_iCDF, 8u); } else { psDec.indices.LTP_scaleIndex = 0; } } psDec.ec_prevSignalType = psDec.indices.signalType; psDec.indices.Seed = (sbyte)psRangeDec.dec_icdf(frameData, Tables.silk_uniform4_iCDF, 8u); } } internal class DecodeParameters { internal static void silk_decode_parameters(SilkChannelDecoder psDec, SilkDecoderControl psDecCtrl, int condCoding) { short[] array = new short[psDec.LPC_order]; short[] array2 = new short[psDec.LPC_order]; BoxedValueSbyte boxedValueSbyte = new BoxedValueSbyte(psDec.LastGainIndex); GainQuantization.silk_gains_dequant(psDecCtrl.Gains_Q16, psDec.indices.GainsIndices, boxedValueSbyte, (condCoding == 2) ? 1 : 0, psDec.nb_subfr); psDec.LastGainIndex = boxedValueSbyte.Val; NLSF.silk_NLSF_decode(array, psDec.indices.NLSFIndices, psDec.psNLSF_CB); NLSF.silk_NLSF2A(psDecCtrl.PredCoef_Q12[1], array, psDec.LPC_order); if (psDec.first_frame_after_reset == 1) { psDec.indices.NLSFInterpCoef_Q2 = 4; } if (psDec.indices.NLSFInterpCoef_Q2 < 4) { for (int i = 0; i < psDec.LPC_order; i++) { array2[i] = (short)(psDec.prevNLSF_Q15[i] + Inlines.silk_RSHIFT(Inlines.silk_MUL(psDec.indices.NLSFInterpCoef_Q2, array[i] - psDec.prevNLSF_Q15[i]), 2)); } NLSF.silk_NLSF2A(psDecCtrl.PredCoef_Q12[0], array2, psDec.LPC_order); } else { Arrays.MemCopy(psDecCtrl.PredCoef_Q12[1], 0, psDecCtrl.PredCoef_Q12[0], 0, psDec.LPC_order); } Arrays.MemCopy(array, 0, psDec.prevNLSF_Q15, 0, psDec.LPC_order); if (psDec.lossCnt != 0) { BWExpander.silk_bwexpander(psDecCtrl.PredCoef_Q12[0], psDec.LPC_order, 63570); BWExpander.silk_bwexpander(psDecCtrl.PredCoef_Q12[1], psDec.LPC_order, 63570); } if (psDec.indices.signalType == 2) { DecodePitch.silk_decode_pitch(psDec.indices.lagIndex, psDec.indices.contourIndex, psDecCtrl.pitchL, psDec.fs_kHz, psDec.nb_subfr); sbyte[][] array3 = Tables.silk_LTP_vq_ptrs_Q7[psDec.indices.PERIndex]; int num; for (int j = 0; j < psDec.nb_subfr; j++) { num = psDec.indices.LTPIndex[j]; for (int i = 0; i < 5; i++) { psDecCtrl.LTPCoef_Q14[j * 5 + i] = (short)Inlines.silk_LSHIFT(array3[num][i], 7); } } num = psDec.indices.LTP_scaleIndex; psDecCtrl.LTP_scale_Q14 = Tables.silk_LTPScales_table_Q14[num]; } else { Arrays.MemSetInt(psDecCtrl.pitchL, 0, psDec.nb_subfr); Arrays.MemSetShort(psDecCtrl.LTPCoef_Q14, 0, 5 * psDec.nb_subfr); psDec.indices.PERIndex = 0; psDecCtrl.LTP_scale_Q14 = 0; } } } internal static class DecodePitch { internal static void silk_decode_pitch(short lagIndex, sbyte contourIndex, int[] pitch_lags, int Fs_kHz, int nb_subfr) { sbyte[][] array = ((Fs_kHz == 8) ? ((nb_subfr != 4) ? Tables.silk_CB_lags_stage2_10_ms : Tables.silk_CB_lags_stage2) : ((nb_subfr != 4) ? Tables.silk_CB_lags_stage3_10_ms : Tables.silk_CB_lags_stage3)); int num = Inlines.silk_SMULBB(2, Fs_kHz); int limit = Inlines.silk_SMULBB(18, Fs_kHz); int num2 = num + lagIndex; for (int i = 0; i < nb_subfr; i++) { pitch_lags[i] = num2 + array[i][contourIndex]; pitch_lags[i] = Inlines.silk_LIMIT(pitch_lags[i], num, limit); } } } internal static class DecodePulses { internal static void silk_decode_pulses(EntropyCoder psRangeDec, ReadOnlySpan frameData, short[] pulses, int signalType, int quantOffsetType, int frame_length) { int[] array = new int[20]; int[] array2 = new int[20]; int num = psRangeDec.dec_icdf(frameData, Tables.silk_rate_levels_iCDF[signalType >> 1], 8u); int num2 = Inlines.silk_RSHIFT(frame_length, 4); if (num2 * 16 < frame_length) { num2++; } for (int i = 0; i < num2; i++) { array2[i] = 0; array[i] = psRangeDec.dec_icdf(frameData, Tables.silk_pulses_per_block_iCDF[num], 8u); while (array[i] == 17) { array2[i]++; array[i] = psRangeDec.dec_icdf(frameData, Tables.silk_pulses_per_block_iCDF[9], (array2[i] == 10) ? 1 : 0, 8u); } } for (int i = 0; i < num2; i++) { if (array[i] > 0) { ShellCoder.silk_shell_decoder(pulses, Inlines.silk_SMULBB(i, 16), psRangeDec, frameData, array[i]); } else { Arrays.MemSetWithOffset(pulses, (short)0, Inlines.silk_SMULBB(i, 16), 16); } } for (int i = 0; i < num2; i++) { if (array2[i] <= 0) { continue; } int num3 = array2[i]; int num4 = Inlines.silk_SMULBB(i, 16); for (int j = 0; j < 16; j++) { int num5 = pulses[num4 + j]; for (int k = 0; k < num3; k++) { num5 = Inlines.silk_LSHIFT(num5, 1); num5 += psRangeDec.dec_icdf(frameData, Tables.silk_lsb_iCDF, 8u); } pulses[num4 + j] = (short)num5; } array[i] |= num3 << 5; } CodeSigns.silk_decode_signs(psRangeDec, frameData, pulses, frame_length, signalType, quantOffsetType, array); } } internal static class EncodeAPI { internal static int silk_InitEncoder(SilkEncoder encState, EncControlState encStatus) { int num = SilkError.SILK_NO_ERROR; encState.Reset(); for (int i = 0; i < 2; i++) { num += SilkEncoder.silk_init_encoder(encState.state_Fxx[i]); } encState.nChannelsAPI = 1; encState.nChannelsInternal = 1; return num + silk_QueryEncoder(encState, encStatus); } internal static int silk_QueryEncoder(SilkEncoder encState, EncControlState encStatus) { int sILK_NO_ERROR = SilkError.SILK_NO_ERROR; SilkChannelEncoder silkChannelEncoder = encState.state_Fxx[0]; encStatus.Reset(); encStatus.nChannelsAPI = encState.nChannelsAPI; encStatus.nChannelsInternal = encState.nChannelsInternal; encStatus.API_sampleRate = silkChannelEncoder.API_fs_Hz; encStatus.maxInternalSampleRate = silkChannelEncoder.maxInternal_fs_Hz; encStatus.minInternalSampleRate = silkChannelEncoder.minInternal_fs_Hz; encStatus.desiredInternalSampleRate = silkChannelEncoder.desiredInternal_fs_Hz; encStatus.payloadSize_ms = silkChannelEncoder.PacketSize_ms; encStatus.bitRate = silkChannelEncoder.TargetRate_bps; encStatus.packetLossPercentage = silkChannelEncoder.PacketLoss_perc; encStatus.complexity = silkChannelEncoder.Complexity; encStatus.useInBandFEC = silkChannelEncoder.useInBandFEC; encStatus.useDTX = silkChannelEncoder.useDTX; encStatus.useCBR = silkChannelEncoder.useCBR; encStatus.internalSampleRate = Inlines.silk_SMULBB(silkChannelEncoder.fs_kHz, 1000); encStatus.allowBandwidthSwitch = silkChannelEncoder.allow_bandwidth_switch; encStatus.inWBmodeWithoutVariableLP = ((silkChannelEncoder.fs_kHz == 16 && silkChannelEncoder.sLP.mode == 0) ? 1 : 0); return sILK_NO_ERROR; } internal static int silk_Encode(SilkEncoder psEnc, EncControlState encControl, short[] samplesIn, int nSamplesIn, EntropyCoder psRangeEnc, Span encodedDataOut, BoxedValueInt nBytesOut, int prefillFlag) { int sILK_NO_ERROR = SilkError.SILK_NO_ERROR; int payloadSize_ms = 0; int complexity = 0; int num = 0; int[] array = new int[2]; nBytesOut.Val = 0; if (encControl.reducedDependency != 0) { psEnc.state_Fxx[0].first_frame_after_reset = 1; psEnc.state_Fxx[1].first_frame_after_reset = 1; } psEnc.state_Fxx[0].nFramesEncoded = (psEnc.state_Fxx[1].nFramesEncoded = 0); sILK_NO_ERROR += encControl.check_control_input(); if (sILK_NO_ERROR != SilkError.SILK_NO_ERROR) { return sILK_NO_ERROR; } encControl.switchReady = 0; if (encControl.nChannelsInternal > psEnc.nChannelsInternal) { sILK_NO_ERROR += SilkEncoder.silk_init_encoder(psEnc.state_Fxx[1]); Arrays.MemSetShort(psEnc.sStereo.pred_prev_Q13, 0, 2); Arrays.MemSetShort(psEnc.sStereo.sSide, 0, 2); psEnc.sStereo.mid_side_amp_Q0[0] = 0; psEnc.sStereo.mid_side_amp_Q0[1] = 1; psEnc.sStereo.mid_side_amp_Q0[2] = 0; psEnc.sStereo.mid_side_amp_Q0[3] = 1; psEnc.sStereo.width_prev_Q14 = 0; psEnc.sStereo.smth_width_Q14 = 16384; if (psEnc.nChannelsAPI == 2) { psEnc.state_Fxx[1].resampler_state.Assign(psEnc.state_Fxx[0].resampler_state); Arrays.MemCopy(psEnc.state_Fxx[0].In_HP_State, 0, psEnc.state_Fxx[1].In_HP_State, 0, 2); } } int num2 = ((encControl.payloadSize_ms != psEnc.state_Fxx[0].PacketSize_ms || psEnc.nChannelsInternal != encControl.nChannelsInternal) ? 1 : 0); psEnc.nChannelsAPI = encControl.nChannelsAPI; psEnc.nChannelsInternal = encControl.nChannelsInternal; int num3 = Inlines.silk_DIV32(100 * nSamplesIn, encControl.API_sampleRate); int num4 = ((num3 <= 1) ? 1 : (num3 >> 1)); int num5 = 0; if (prefillFlag != 0) { if (num3 != 1) { return SilkError.SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; } for (int i = 0; i < encControl.nChannelsInternal; i++) { sILK_NO_ERROR += SilkEncoder.silk_init_encoder(psEnc.state_Fxx[i]); } payloadSize_ms = encControl.payloadSize_ms; encControl.payloadSize_ms = 10; complexity = encControl.complexity; encControl.complexity = 0; for (int i = 0; i < encControl.nChannelsInternal; i++) { psEnc.state_Fxx[i].controlled_since_last_payload = 0; psEnc.state_Fxx[i].prefillFlag = 1; } } else { if (num3 * encControl.API_sampleRate != 100 * nSamplesIn || nSamplesIn < 0) { return SilkError.SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; } if (1000 * nSamplesIn > encControl.payloadSize_ms * encControl.API_sampleRate) { return SilkError.SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; } } int targetRate_bps = Inlines.silk_RSHIFT32(encControl.bitRate, encControl.nChannelsInternal - 1); for (int i = 0; i < encControl.nChannelsInternal; i++) { int force_fs_kHz = ((i == 1) ? psEnc.state_Fxx[0].fs_kHz : 0); sILK_NO_ERROR += psEnc.state_Fxx[i].silk_control_encoder(encControl, targetRate_bps, psEnc.allowBandwidthSwitch, i, force_fs_kHz); if (sILK_NO_ERROR != SilkError.SILK_NO_ERROR) { return sILK_NO_ERROR; } if (psEnc.state_Fxx[i].first_frame_after_reset != 0 || num2 != 0) { for (int j = 0; j < psEnc.state_Fxx[0].nFramesPerPacket; j++) { psEnc.state_Fxx[i].LBRR_flags[j] = 0; } } psEnc.state_Fxx[i].inDTX = psEnc.state_Fxx[i].useDTX; } int num6 = 10 * num3 * psEnc.state_Fxx[0].fs_kHz; short[] array2 = new short[Inlines.silk_DIV32_16(num6 * psEnc.state_Fxx[0].API_fs_Hz, (short)(psEnc.state_Fxx[0].fs_kHz * 1000))]; int num7 = 0; while (true) { int a = psEnc.state_Fxx[0].frame_length - psEnc.state_Fxx[0].inputBufIx; a = Inlines.silk_min(a, num6); num = Inlines.silk_DIV32_16(a * psEnc.state_Fxx[0].API_fs_Hz, psEnc.state_Fxx[0].fs_kHz * 1000); if (encControl.nChannelsAPI == 2 && encControl.nChannelsInternal == 2) { int nFramesEncoded = psEnc.state_Fxx[0].nFramesEncoded; for (int i = 0; i < num; i++) { array2[i] = samplesIn[num7 + 2 * i]; } if (psEnc.nPrevChannelsInternal == 1 && nFramesEncoded == 0) { psEnc.state_Fxx[1].resampler_state.Assign(psEnc.state_Fxx[0].resampler_state); } sILK_NO_ERROR += Resampler.silk_resampler(psEnc.state_Fxx[0].resampler_state, psEnc.state_Fxx[0].inputBuf, psEnc.state_Fxx[0].inputBufIx + 2, array2, 0, num); psEnc.state_Fxx[0].inputBufIx += a; a = psEnc.state_Fxx[1].frame_length - psEnc.state_Fxx[1].inputBufIx; a = Inlines.silk_min(a, 10 * num3 * psEnc.state_Fxx[1].fs_kHz); for (int i = 0; i < num; i++) { array2[i] = samplesIn[num7 + 2 * i + 1]; } sILK_NO_ERROR += Resampler.silk_resampler(psEnc.state_Fxx[1].resampler_state, psEnc.state_Fxx[1].inputBuf, psEnc.state_Fxx[1].inputBufIx + 2, array2, 0, num); psEnc.state_Fxx[1].inputBufIx += a; } else if (encControl.nChannelsAPI == 2 && encControl.nChannelsInternal == 1) { for (int i = 0; i < num; i++) { int a2 = samplesIn[num7 + 2 * i] + samplesIn[num7 + 2 * i + 1]; array2[i] = (short)Inlines.silk_RSHIFT_ROUND(a2, 1); } sILK_NO_ERROR += Resampler.silk_resampler(psEnc.state_Fxx[0].resampler_state, psEnc.state_Fxx[0].inputBuf, psEnc.state_Fxx[0].inputBufIx + 2, array2, 0, num); if (psEnc.nPrevChannelsInternal == 2 && psEnc.state_Fxx[0].nFramesEncoded == 0) { sILK_NO_ERROR += Resampler.silk_resampler(psEnc.state_Fxx[1].resampler_state, psEnc.state_Fxx[1].inputBuf, psEnc.state_Fxx[1].inputBufIx + 2, array2, 0, num); for (int i = 0; i < psEnc.state_Fxx[0].frame_length; i++) { psEnc.state_Fxx[0].inputBuf[psEnc.state_Fxx[0].inputBufIx + i + 2] = (short)Inlines.silk_RSHIFT(psEnc.state_Fxx[0].inputBuf[psEnc.state_Fxx[0].inputBufIx + i + 2] + psEnc.state_Fxx[1].inputBuf[psEnc.state_Fxx[1].inputBufIx + i + 2], 1); } } psEnc.state_Fxx[0].inputBufIx += a; } else { Arrays.MemCopy(samplesIn, num7, array2, 0, num); sILK_NO_ERROR += Resampler.silk_resampler(psEnc.state_Fxx[0].resampler_state, psEnc.state_Fxx[0].inputBuf, psEnc.state_Fxx[0].inputBufIx + 2, array2, 0, num); psEnc.state_Fxx[0].inputBufIx += a; } num7 += num * encControl.nChannelsAPI; nSamplesIn -= num; psEnc.allowBandwidthSwitch = 0; if (psEnc.state_Fxx[0].inputBufIx < psEnc.state_Fxx[0].frame_length) { break; } if (psEnc.state_Fxx[0].nFramesEncoded == 0 && prefillFlag == 0) { psRangeEnc.enc_icdf(encodedDataOut, 0, new byte[2] { (byte)(256 - Inlines.silk_RSHIFT(256, (psEnc.state_Fxx[0].nFramesPerPacket + 1) * encControl.nChannelsInternal)), 0 }, 8u); for (int i = 0; i < encControl.nChannelsInternal; i++) { int num8 = 0; for (int j = 0; j < psEnc.state_Fxx[i].nFramesPerPacket; j++) { num8 |= Inlines.silk_LSHIFT(psEnc.state_Fxx[i].LBRR_flags[j], j); } psEnc.state_Fxx[i].LBRR_flag = ((num8 > 0) ? ((sbyte)1) : ((sbyte)0)); if (num8 != 0 && psEnc.state_Fxx[i].nFramesPerPacket > 1) { psRangeEnc.enc_icdf(encodedDataOut, num8 - 1, Tables.silk_LBRR_flags_iCDF_ptr[psEnc.state_Fxx[i].nFramesPerPacket - 2], 8u); } } for (int j = 0; j < psEnc.state_Fxx[0].nFramesPerPacket; j++) { for (int i = 0; i < encControl.nChannelsInternal; i++) { if (psEnc.state_Fxx[i].LBRR_flags[j] == 0) { continue; } if (encControl.nChannelsInternal == 2 && i == 0) { Stereo.silk_stereo_encode_pred(psRangeEnc, encodedDataOut, psEnc.sStereo.predIx[j]); if (psEnc.state_Fxx[1].LBRR_flags[j] == 0) { Stereo.silk_stereo_encode_mid_only(psRangeEnc, encodedDataOut, psEnc.sStereo.mid_only_flags[j]); } } EncodeIndices.silk_encode_indices(condCoding: (j > 0 && psEnc.state_Fxx[i].LBRR_flags[j - 1] != 0) ? 2 : 0, psEncC: psEnc.state_Fxx[i], psRangeEnc: psRangeEnc, encodedDataOut: encodedDataOut, FrameIndex: j, encode_LBRR: 1); EncodePulses.silk_encode_pulses(psRangeEnc, encodedDataOut, psEnc.state_Fxx[i].indices_LBRR[j].signalType, psEnc.state_Fxx[i].indices_LBRR[j].quantOffsetType, psEnc.state_Fxx[i].pulses_LBRR[j], psEnc.state_Fxx[i].frame_length); } } for (int i = 0; i < encControl.nChannelsInternal; i++) { Arrays.MemSetInt(psEnc.state_Fxx[i].LBRR_flags, 0, 3); } psEnc.nBitsUsedLBRR = psRangeEnc.tell(); } HPVariableCutoff.silk_HP_variable_cutoff(psEnc.state_Fxx); int num9 = Inlines.silk_DIV32_16(Inlines.silk_MUL(encControl.bitRate, encControl.payloadSize_ms), 1000); if (prefillFlag == 0) { num9 -= psEnc.nBitsUsedLBRR; } num9 = Inlines.silk_DIV32_16(num9, psEnc.state_Fxx[0].nFramesPerPacket); targetRate_bps = ((encControl.payloadSize_ms != 10) ? Inlines.silk_SMULBB(num9, 50) : Inlines.silk_SMULBB(num9, 100)); targetRate_bps -= Inlines.silk_DIV32_16(Inlines.silk_MUL(psEnc.nBitsExceeded, 1000), 500); if (prefillFlag == 0 && psEnc.state_Fxx[0].nFramesEncoded > 0) { int a3 = psRangeEnc.tell() - psEnc.nBitsUsedLBRR - num9 * psEnc.state_Fxx[0].nFramesEncoded; targetRate_bps -= Inlines.silk_DIV32_16(Inlines.silk_MUL(a3, 1000), 500); } targetRate_bps = Inlines.silk_LIMIT(targetRate_bps, encControl.bitRate, 5000); if (encControl.nChannelsInternal == 2) { BoxedValueSbyte boxedValueSbyte = new BoxedValueSbyte(psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded]); Stereo.silk_stereo_LR_to_MS(psEnc.sStereo, psEnc.state_Fxx[0].inputBuf, 2, psEnc.state_Fxx[1].inputBuf, 2, psEnc.sStereo.predIx[psEnc.state_Fxx[0].nFramesEncoded], boxedValueSbyte, array, targetRate_bps, psEnc.state_Fxx[0].speech_activity_Q8, encControl.toMono, psEnc.state_Fxx[0].fs_kHz, psEnc.state_Fxx[0].frame_length); psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded] = boxedValueSbyte.Val; if (boxedValueSbyte.Val == 0) { if (psEnc.prev_decode_only_middle == 1) { psEnc.state_Fxx[1].sShape.Reset(); psEnc.state_Fxx[1].sPrefilt.Reset(); psEnc.state_Fxx[1].sNSQ.Reset(); Arrays.MemSetShort(psEnc.state_Fxx[1].prev_NLSFq_Q15, 0, 16); Arrays.MemSetInt(psEnc.state_Fxx[1].sLP.In_LP_State, 0, 2); psEnc.state_Fxx[1].prevLag = 100; psEnc.state_Fxx[1].sNSQ.lagPrev = 100; psEnc.state_Fxx[1].sShape.LastGainIndex = 10; psEnc.state_Fxx[1].prevSignalType = 0; psEnc.state_Fxx[1].sNSQ.prev_gain_Q16 = 65536; psEnc.state_Fxx[1].first_frame_after_reset = 1; } psEnc.state_Fxx[1].silk_encode_do_VAD(); } else { psEnc.state_Fxx[1].VAD_flags[psEnc.state_Fxx[0].nFramesEncoded] = 0; } if (prefillFlag == 0) { Stereo.silk_stereo_encode_pred(psRangeEnc, encodedDataOut, psEnc.sStereo.predIx[psEnc.state_Fxx[0].nFramesEncoded]); if (psEnc.state_Fxx[1].VAD_flags[psEnc.state_Fxx[0].nFramesEncoded] == 0) { Stereo.silk_stereo_encode_mid_only(psRangeEnc, encodedDataOut, psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded]); } } } else { Arrays.MemCopy(psEnc.sStereo.sMid, 0, psEnc.state_Fxx[0].inputBuf, 0, 2); Arrays.MemCopy(psEnc.state_Fxx[0].inputBuf, psEnc.state_Fxx[0].frame_length, psEnc.sStereo.sMid, 0, 2); } psEnc.state_Fxx[0].silk_encode_do_VAD(); for (int i = 0; i < encControl.nChannelsInternal; i++) { int num10 = encControl.maxBits; if (num4 == 2 && num5 == 0) { num10 = num10 * 3 / 5; } else if (num4 == 3) { switch (num5) { case 0: num10 = num10 * 2 / 5; break; case 1: num10 = num10 * 3 / 4; break; } } int useCBR = ((encControl.useCBR != 0 && num5 == num4 - 1) ? 1 : 0); int num11; if (encControl.nChannelsInternal == 1) { num11 = targetRate_bps; } else { num11 = array[i]; if (i == 0 && array[1] > 0) { useCBR = 0; num10 -= encControl.maxBits / (num4 * 2); } } if (num11 > 0) { psEnc.state_Fxx[i].silk_control_SNR(num11); int condCoding2 = ((psEnc.state_Fxx[0].nFramesEncoded - i > 0) ? ((i > 0 && psEnc.prev_decode_only_middle != 0) ? 1 : 2) : 0); sILK_NO_ERROR += psEnc.state_Fxx[i].silk_encode_frame(nBytesOut, psRangeEnc, encodedDataOut, condCoding2, num10, useCBR); } psEnc.state_Fxx[i].controlled_since_last_payload = 0; psEnc.state_Fxx[i].inputBufIx = 0; psEnc.state_Fxx[i].nFramesEncoded++; } psEnc.prev_decode_only_middle = psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded - 1]; if (nBytesOut.Val > 0 && psEnc.state_Fxx[0].nFramesEncoded == psEnc.state_Fxx[0].nFramesPerPacket) { int num12 = 0; for (int i = 0; i < encControl.nChannelsInternal; i++) { for (int j = 0; j < psEnc.state_Fxx[i].nFramesPerPacket; j++) { num12 = Inlines.silk_LSHIFT(num12, 1); num12 |= psEnc.state_Fxx[i].VAD_flags[j]; } num12 = Inlines.silk_LSHIFT(num12, 1); num12 |= psEnc.state_Fxx[i].LBRR_flag; } if (prefillFlag == 0) { psRangeEnc.enc_patch_initial_bits(encodedDataOut, (uint)num12, (uint)((psEnc.state_Fxx[0].nFramesPerPacket + 1) * encControl.nChannelsInternal)); } if (psEnc.state_Fxx[0].inDTX != 0 && (encControl.nChannelsInternal == 1 || psEnc.state_Fxx[1].inDTX != 0)) { nBytesOut.Val = 0; } psEnc.nBitsExceeded += nBytesOut.Val * 8; psEnc.nBitsExceeded -= Inlines.silk_DIV32_16(Inlines.silk_MUL(encControl.bitRate, encControl.payloadSize_ms), 1000); psEnc.nBitsExceeded = Inlines.silk_LIMIT(psEnc.nBitsExceeded, 0, 10000); int num13 = Inlines.silk_SMLAWB(13, 3188, psEnc.timeSinceSwitchAllowed_ms); if (psEnc.state_Fxx[0].speech_activity_Q8 < num13) { psEnc.allowBandwidthSwitch = 1; psEnc.timeSinceSwitchAllowed_ms = 0; } else { psEnc.allowBandwidthSwitch = 0; psEnc.timeSinceSwitchAllowed_ms += encControl.payloadSize_ms; } } if (nSamplesIn == 0) { break; } num5++; } psEnc.nPrevChannelsInternal = encControl.nChannelsInternal; encControl.allowBandwidthSwitch = psEnc.allowBandwidthSwitch; encControl.inWBmodeWithoutVariableLP = ((psEnc.state_Fxx[0].fs_kHz == 16 && psEnc.state_Fxx[0].sLP.mode == 0) ? 1 : 0); encControl.internalSampleRate = Inlines.silk_SMULBB(psEnc.state_Fxx[0].fs_kHz, 1000); encControl.stereoWidth_Q14 = ((encControl.toMono == 0) ? psEnc.sStereo.smth_width_Q14 : 0); if (prefillFlag != 0) { encControl.payloadSize_ms = payloadSize_ms; encControl.complexity = complexity; for (int i = 0; i < encControl.nChannelsInternal; i++) { psEnc.state_Fxx[i].controlled_since_last_payload = 0; psEnc.state_Fxx[i].prefillFlag = 0; } } return sILK_NO_ERROR; } } internal static class EncodeIndices { internal static void silk_encode_indices(SilkChannelEncoder psEncC, EntropyCoder psRangeEnc, Span encodedDataOut, int FrameIndex, int encode_LBRR, int condCoding) { short[] array = new short[16]; byte[] array2 = new byte[16]; SideInfoIndices sideInfoIndices = ((encode_LBRR == 0) ? psEncC.indices : psEncC.indices_LBRR[FrameIndex]); int num = 2 * sideInfoIndices.signalType + sideInfoIndices.quantOffsetType; if (encode_LBRR != 0 || num >= 2) { psRangeEnc.enc_icdf(encodedDataOut, num - 2, Tables.silk_type_offset_VAD_iCDF, 8u); } else { psRangeEnc.enc_icdf(encodedDataOut, num, Tables.silk_type_offset_no_VAD_iCDF, 8u); } if (condCoding == 2) { psRangeEnc.enc_icdf(encodedDataOut, sideInfoIndices.GainsIndices[0], Tables.silk_delta_gain_iCDF, 8u); } else { psRangeEnc.enc_icdf(encodedDataOut, Inlines.silk_RSHIFT(sideInfoIndices.GainsIndices[0], 3), Tables.silk_gain_iCDF[sideInfoIndices.signalType], 8u); psRangeEnc.enc_icdf(encodedDataOut, sideInfoIndices.GainsIndices[0] & 7, Tables.silk_uniform8_iCDF, 8u); } for (int i = 1; i < psEncC.nb_subfr; i++) { psRangeEnc.enc_icdf(encodedDataOut, sideInfoIndices.GainsIndices[i], Tables.silk_delta_gain_iCDF, 8u); } psRangeEnc.enc_icdf(encodedDataOut, sideInfoIndices.NLSFIndices[0], psEncC.psNLSF_CB.CB1_iCDF, (sideInfoIndices.signalType >> 1) * psEncC.psNLSF_CB.nVectors, 8u); NLSF.silk_NLSF_unpack(array, array2, psEncC.psNLSF_CB, sideInfoIndices.NLSFIndices[0]); for (int i = 0; i < psEncC.psNLSF_CB.order; i++) { if (sideInfoIndices.NLSFIndices[i + 1] >= 4) { psRangeEnc.enc_icdf(encodedDataOut, 8, psEncC.psNLSF_CB.ec_iCDF, array[i], 8u); psRangeEnc.enc_icdf(encodedDataOut, sideInfoIndices.NLSFIndices[i + 1] - 4, Tables.silk_NLSF_EXT_iCDF, 8u); } else if (sideInfoIndices.NLSFIndices[i + 1] <= -4) { psRangeEnc.enc_icdf(encodedDataOut, 0, psEncC.psNLSF_CB.ec_iCDF, array[i], 8u); psRangeEnc.enc_icdf(encodedDataOut, -sideInfoIndices.NLSFIndices[i + 1] - 4, Tables.silk_NLSF_EXT_iCDF, 8u); } else { psRangeEnc.enc_icdf(encodedDataOut, sideInfoIndices.NLSFIndices[i + 1] + 4, psEncC.psNLSF_CB.ec_iCDF, array[i], 8u); } } if (psEncC.nb_subfr == 4) { psRangeEnc.enc_icdf(encodedDataOut, sideInfoIndices.NLSFInterpCoef_Q2, Tables.silk_NLSF_interpolation_factor_iCDF, 8u); } if (sideInfoIndices.signalType == 2) { int num2 = 1; if (condCoding == 2 && psEncC.ec_prevSignalType == 2) { int num3 = sideInfoIndices.lagIndex - psEncC.ec_prevLagIndex; if (num3 < -8 || num3 > 11) { num3 = 0; } else { num3 += 9; num2 = 0; } psRangeEnc.enc_icdf(encodedDataOut, num3, Tables.silk_pitch_delta_iCDF, 8u); } if (num2 != 0) { int num4 = Inlines.silk_DIV32_16(sideInfoIndices.lagIndex, Inlines.silk_RSHIFT(psEncC.fs_kHz, 1)); int s = sideInfoIndices.lagIndex - Inlines.silk_SMULBB(num4, Inlines.silk_RSHIFT(psEncC.fs_kHz, 1)); psRangeEnc.enc_icdf(encodedDataOut, num4, Tables.silk_pitch_lag_iCDF, 8u); psRangeEnc.enc_icdf(encodedDataOut, s, psEncC.pitch_lag_low_bits_iCDF, 8u); } psEncC.ec_prevLagIndex = sideInfoIndices.lagIndex; psRangeEnc.enc_icdf(encodedDataOut, sideInfoIndices.contourIndex, psEncC.pitch_contour_iCDF, 8u); psRangeEnc.enc_icdf(encodedDataOut, sideInfoIndices.PERIndex, Tables.silk_LTP_per_index_iCDF, 8u); for (int j = 0; j < psEncC.nb_subfr; j++) { psRangeEnc.enc_icdf(encodedDataOut, sideInfoIndices.LTPIndex[j], Tables.silk_LTP_gain_iCDF_ptrs[sideInfoIndices.PERIndex], 8u); } if (condCoding == 0) { psRangeEnc.enc_icdf(encodedDataOut, sideInfoIndices.LTP_scaleIndex, Tables.silk_LTPscale_iCDF, 8u); } } psEncC.ec_prevSignalType = sideInfoIndices.signalType; psRangeEnc.enc_icdf(encodedDataOut, sideInfoIndices.Seed, Tables.silk_uniform4_iCDF, 8u); } } internal static class EncodePulses { internal static int combine_and_check(Span pulses_comb, int pulses_comb_ptr, Span pulses_in, int pulses_in_ptr, int max_pulses, int len) { for (int i = 0; i < len; i++) { int num = 2 * i + pulses_in_ptr; int num2 = pulses_in[num] + pulses_in[num + 1]; if (num2 > max_pulses) { return 1; } pulses_comb[pulses_comb_ptr + i] = num2; } return 0; } internal static int combine_and_check(int[] pulses_comb, int[] pulses_in, int max_pulses, int len) { for (int i = 0; i < len; i++) { int num = pulses_in[2 * i] + pulses_in[2 * i + 1]; if (num > max_pulses) { return 1; } pulses_comb[i] = num; } return 0; } internal static void silk_encode_pulses(EntropyCoder psRangeEnc, Span encodedDataOut, int signalType, int quantOffsetType, Span pulses, int frame_length) { int num = 0; int[] array = new int[8]; Arrays.MemSetInt(array, 0, 8); int num2 = Inlines.silk_RSHIFT(frame_length, 4); if (num2 * 16 < frame_length) { num2++; Arrays.MemSetWithOffset(pulses, 0, frame_length, 16); } int[] array2 = new int[num2 * 16]; for (int i = 0; i < num2 * 16; i += 4) { array2[i] = Inlines.silk_abs(pulses[i]); array2[i + 1] = Inlines.silk_abs(pulses[i + 1]); array2[i + 2] = Inlines.silk_abs(pulses[i + 2]); array2[i + 3] = Inlines.silk_abs(pulses[i + 3]); } int[] array3 = new int[num2]; int[] array4 = new int[num2]; int num3 = 0; for (int i = 0; i < num2; i++) { array4[i] = 0; while (combine_and_check(array, 0, array2, num3, Tables.silk_max_pulses_table[0], 8) + combine_and_check(array, array, Tables.silk_max_pulses_table[1], 4) + combine_and_check(array, array, Tables.silk_max_pulses_table[2], 2) + combine_and_check(array3, i, array, 0, Tables.silk_max_pulses_table[3], 1) != 0) { array4[i]++; for (int j = num3; j < num3 + 16; j++) { array2[j] = Inlines.silk_RSHIFT(array2[j], 1); } } num3 += 16; } int num4 = int.MaxValue; for (int j = 0; j < 9; j++) { byte[] array5 = Tables.silk_pulses_per_block_BITS_Q5[j]; int num5 = Tables.silk_rate_levels_BITS_Q5[signalType >> 1][j]; for (int i = 0; i < num2; i++) { num5 = ((array4[i] <= 0) ? (num5 + array5[array3[i]]) : (num5 + array5[17])); } if (num5 < num4) { num4 = num5; num = j; } } psRangeEnc.enc_icdf(encodedDataOut, num, Tables.silk_rate_levels_iCDF[signalType >> 1], 8u); for (int i = 0; i < num2; i++) { if (array4[i] == 0) { psRangeEnc.enc_icdf(encodedDataOut, array3[i], Tables.silk_pulses_per_block_iCDF[num], 8u); continue; } psRangeEnc.enc_icdf(encodedDataOut, 17, Tables.silk_pulses_per_block_iCDF[num], 8u); for (int j = 0; j < array4[i] - 1; j++) { psRangeEnc.enc_icdf(encodedDataOut, 17, Tables.silk_pulses_per_block_iCDF[9], 8u); } psRangeEnc.enc_icdf(encodedDataOut, array3[i], Tables.silk_pulses_per_block_iCDF[9], 8u); } for (int i = 0; i < num2; i++) { if (array3[i] > 0) { ShellCoder.silk_shell_encoder(psRangeEnc, encodedDataOut, array2, i * 16); } } for (int i = 0; i < num2; i++) { if (array4[i] <= 0) { continue; } int num6 = i * 16; int num7 = array4[i] - 1; for (int j = 0; j < 16; j++) { int num8 = (sbyte)Inlines.silk_abs(pulses[num6 + j]); int s; for (int num9 = num7; num9 > 0; num9--) { s = Inlines.silk_RSHIFT(num8, num9) & 1; psRangeEnc.enc_icdf(encodedDataOut, s, Tables.silk_lsb_iCDF, 8u); } s = num8 & 1; psRangeEnc.enc_icdf(encodedDataOut, s, Tables.silk_lsb_iCDF, 8u); } } CodeSigns.silk_encode_signs(psRangeEnc, encodedDataOut, pulses, frame_length, signalType, quantOffsetType, array3); } } internal static class Filters { private static readonly short A_fb1_20 = 10788; private static readonly short A_fb1_21 = -24290; private const int QA = 24; private static readonly int A_LIMIT = 16773022; internal static void silk_warped_LPC_analysis_filter(int[] state, int[] res_Q2, short[] coef_Q13, int coef_Q13_ptr, short[] input, int input_ptr, short lambda_Q16, int length, int order) { for (int i = 0; i < length; i++) { int num = Inlines.silk_SMLAWB(state[0], state[1], lambda_Q16); state[0] = Inlines.silk_LSHIFT(input[input_ptr + i], 14); int num2 = Inlines.silk_SMLAWB(state[1], state[2] - num, lambda_Q16); state[1] = num; int a = Inlines.silk_RSHIFT(order, 1); a = Inlines.silk_SMLAWB(a, num, coef_Q13[coef_Q13_ptr]); for (int j = 2; j < order; j += 2) { num = Inlines.silk_SMLAWB(state[j], state[j + 1] - num2, lambda_Q16); state[j] = num2; a = Inlines.silk_SMLAWB(a, num2, coef_Q13[coef_Q13_ptr + j - 1]); num2 = Inlines.silk_SMLAWB(state[j + 1], state[j + 2] - num, lambda_Q16); state[j + 1] = num; a = Inlines.silk_SMLAWB(a, num, coef_Q13[coef_Q13_ptr + j]); } state[order] = num2; a = Inlines.silk_SMLAWB(a, num2, coef_Q13[coef_Q13_ptr + order - 1]); res_Q2[i] = Inlines.silk_LSHIFT(input[input_ptr + i], 2) - Inlines.silk_RSHIFT_ROUND(a, 9); } } internal static void silk_prefilter(SilkChannelEncoder psEnc, SilkEncoderControl psEncCtrl, int[] xw_Q3, short[] x, int x_ptr) { SilkPrefilterState sPrefilt = psEnc.sPrefilt; Span span = stackalloc short[2]; int num = x_ptr; int num2 = 0; int lag = sPrefilt.lagPrev; int[] array = new int[psEnc.subfr_length]; int[] array2 = new int[psEnc.subfr_length]; for (int i = 0; i < psEnc.nb_subfr; i++) { if (psEnc.indices.signalType == 2) { lag = psEncCtrl.pitchL[i]; } int num3 = Inlines.silk_SMULWB(psEncCtrl.HarmShapeGain_Q14[i], 16384 - psEncCtrl.HarmBoost_Q14[i]); int num4 = Inlines.silk_RSHIFT(num3, 2); num4 |= Inlines.silk_LSHIFT(Inlines.silk_RSHIFT(num3, 1), 16); int tilt_Q = psEncCtrl.Tilt_Q14[i]; int lF_shp_Q = psEncCtrl.LF_shp_Q14[i]; int coef_Q13_ptr = i * 16; silk_warped_LPC_analysis_filter(sPrefilt.sAR_shp, array2, psEncCtrl.AR1_Q13, coef_Q13_ptr, x, num, (short)psEnc.warping_Q16, psEnc.subfr_length, psEnc.shapingLPCOrder); span[0] = (short)Inlines.silk_RSHIFT_ROUND(psEncCtrl.GainsPre_Q14[i], 4); int a = Inlines.silk_SMLABB(3355443, psEncCtrl.HarmBoost_Q14[i], num3); a = Inlines.silk_SMLABB(a, psEncCtrl.coding_quality_Q14, 410); a = Inlines.silk_SMULWB(a, -psEncCtrl.GainsPre_Q14[i]); a = Inlines.silk_RSHIFT_ROUND(a, 14); span[1] = (short)Inlines.silk_SAT16(a); array[0] = Inlines.silk_MLA(Inlines.silk_MUL(array2[0], span[0]), sPrefilt.sHarmHP_Q2, span[1]); for (int j = 1; j < psEnc.subfr_length; j++) { array[j] = Inlines.silk_MLA(Inlines.silk_MUL(array2[j], span[0]), array2[j - 1], span[1]); } sPrefilt.sHarmHP_Q2 = array2[psEnc.subfr_length - 1]; silk_prefilt(sPrefilt, array, xw_Q3, num2, num4, tilt_Q, lF_shp_Q, lag, psEnc.subfr_length); num += psEnc.subfr_length; num2 += psEnc.subfr_length; } sPrefilt.lagPrev = psEncCtrl.pitchL[psEnc.nb_subfr - 1]; } private static void silk_prefilt(SilkPrefilterState P, int[] st_res_Q12, int[] xw_Q3, int xw_Q3_ptr, int HarmShapeFIRPacked_Q12, int Tilt_Q14, int LF_shp_Q14, int lag, int length) { short[] sLTP_shp = P.sLTP_shp; int num = P.sLTP_shp_buf_idx; int num2 = P.sLF_AR_shp_Q12; int num3 = P.sLF_MA_shp_Q12; for (int i = 0; i < length; i++) { int a; if (lag > 0) { int num4 = lag + num; a = Inlines.silk_SMULBB(sLTP_shp[(num4 - 1 - 1) & 0x1FF], HarmShapeFIRPacked_Q12); a = Inlines.silk_SMLABT(a, sLTP_shp[(num4 - 1) & 0x1FF], HarmShapeFIRPacked_Q12); a = Inlines.silk_SMLABB(a, sLTP_shp[(num4 - 1 + 1) & 0x1FF], HarmShapeFIRPacked_Q12); } else { a = 0; } int a2 = Inlines.silk_SMULWB(num2, Tilt_Q14); int a3 = Inlines.silk_SMLAWB(Inlines.silk_SMULWT(num2, LF_shp_Q14), num3, LF_shp_Q14); num2 = Inlines.silk_SUB32(st_res_Q12[i], Inlines.silk_LSHIFT(a2, 2)); num3 = Inlines.silk_SUB32(num2, Inlines.silk_LSHIFT(a3, 2)); num = (num - 1) & 0x1FF; sLTP_shp[num] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(num3, 12)); xw_Q3[xw_Q3_ptr + i] = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SUB32(num3, a), 9); } P.sLF_AR_shp_Q12 = num2; P.sLF_MA_shp_Q12 = num3; P.sLTP_shp_buf_idx = num; } internal static void silk_biquad_alt(ReadOnlySpan input, int input_ptr, int[] B_Q28, int[] A_Q28, int[] S, Span output, int output_ptr, int len, int stride) { int b = -A_Q28[0] & 0x3FFF; int c = Inlines.silk_RSHIFT(-A_Q28[0], 14); int b2 = -A_Q28[1] & 0x3FFF; int c2 = Inlines.silk_RSHIFT(-A_Q28[1], 14); for (int i = 0; i < len; i++) { int c3 = input[input_ptr + i * stride]; int num = Inlines.silk_LSHIFT(Inlines.silk_SMLAWB(S[0], B_Q28[0], c3), 2); S[0] = S[1] + Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(num, b), 14); S[0] = Inlines.silk_SMLAWB(S[0], num, c); S[0] = Inlines.silk_SMLAWB(S[0], B_Q28[1], c3); S[1] = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(num, b2), 14); S[1] = Inlines.silk_SMLAWB(S[1], num, c2); S[1] = Inlines.silk_SMLAWB(S[1], B_Q28[2], c3); output[output_ptr + i * stride] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(num + 16384 - 1, 14)); } } internal static void silk_biquad_alt(ReadOnlySpan input, int input_ptr, int[] B_Q28, int[] A_Q28, Span S, int S_ptr, Span output, int output_ptr, int len, int stride) { int b = -A_Q28[0] & 0x3FFF; int c = Inlines.silk_RSHIFT(-A_Q28[0], 14); int b2 = -A_Q28[1] & 0x3FFF; int c2 = Inlines.silk_RSHIFT(-A_Q28[1], 14); for (int i = 0; i < len; i++) { int index = S_ptr + 1; int c3 = input[input_ptr + i * stride]; int num = Inlines.silk_LSHIFT(Inlines.silk_SMLAWB(S[S_ptr], B_Q28[0], c3), 2); S[S_ptr] = S[index] + Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(num, b), 14); S[S_ptr] = Inlines.silk_SMLAWB(S[S_ptr], num, c); S[S_ptr] = Inlines.silk_SMLAWB(S[S_ptr], B_Q28[1], c3); S[index] = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWB(num, b2), 14); S[index] = Inlines.silk_SMLAWB(S[index], num, c2); S[index] = Inlines.silk_SMLAWB(S[index], B_Q28[2], c3); output[output_ptr + i * stride] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(num + 16384 - 1, 14)); } } internal static void silk_ana_filt_bank_1(Span input, int input_ptr, int[] S, short[] outL, Span outH, int outH_ptr, int N) { int num = Inlines.silk_RSHIFT(N, 1); for (int i = 0; i < num; i++) { int a = Inlines.silk_LSHIFT(input[input_ptr + 2 * i], 10); int num2 = Inlines.silk_SUB32(a, S[0]); int b = Inlines.silk_SMLAWB(num2, num2, A_fb1_21); int b2 = Inlines.silk_ADD32(S[0], b); S[0] = Inlines.silk_ADD32(a, b); a = Inlines.silk_LSHIFT(input[input_ptr + 2 * i + 1], 10); b = Inlines.silk_SMULWB(Inlines.silk_SUB32(a, S[1]), A_fb1_20); int a2 = Inlines.silk_ADD32(S[1], b); S[1] = Inlines.silk_ADD32(a, b); outL[i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_ADD32(a2, b2), 11)); outH[outH_ptr + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SUB32(a2, b2), 11)); } } 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_LP_interpolate_filter_taps(int[] B_Q28, int[] A_Q28, int ind, int fac_Q16) { if (ind < 4) { if (fac_Q16 > 0) { if (fac_Q16 < 32768) { for (int i = 0; i < 3; i++) { B_Q28[i] = Inlines.silk_SMLAWB(Tables.silk_Transition_LP_B_Q28[ind][i], Tables.silk_Transition_LP_B_Q28[ind + 1][i] - Tables.silk_Transition_LP_B_Q28[ind][i], fac_Q16); } for (int j = 0; j < 2; j++) { A_Q28[j] = Inlines.silk_SMLAWB(Tables.silk_Transition_LP_A_Q28[ind][j], Tables.silk_Transition_LP_A_Q28[ind + 1][j] - Tables.silk_Transition_LP_A_Q28[ind][j], fac_Q16); } } else { for (int i = 0; i < 3; i++) { B_Q28[i] = Inlines.silk_SMLAWB(Tables.silk_Transition_LP_B_Q28[ind + 1][i], Tables.silk_Transition_LP_B_Q28[ind + 1][i] - Tables.silk_Transition_LP_B_Q28[ind][i], fac_Q16 - 65536); } for (int j = 0; j < 2; j++) { A_Q28[j] = Inlines.silk_SMLAWB(Tables.silk_Transition_LP_A_Q28[ind + 1][j], Tables.silk_Transition_LP_A_Q28[ind + 1][j] - Tables.silk_Transition_LP_A_Q28[ind][j], fac_Q16 - 65536); } } } else { Arrays.MemCopy(Tables.silk_Transition_LP_B_Q28[ind], 0, B_Q28, 0, 3); Arrays.MemCopy(Tables.silk_Transition_LP_A_Q28[ind], 0, A_Q28, 0, 2); } } else { Arrays.MemCopy(Tables.silk_Transition_LP_B_Q28[4], 0, B_Q28, 0, 3); Arrays.MemCopy(Tables.silk_Transition_LP_A_Q28[4], 0, A_Q28, 0, 2); } } internal static void silk_LPC_analysis_filter(Span output, int output_ptr, Span input, int input_ptr, Span B, int B_ptr, int len, int d) { Span mem = stackalloc short[16]; Span num = stackalloc short[16]; for (int i = 0; i < d; i++) { num[i] = (short)(-B[B_ptr + i]); } for (int i = 0; i < d; i++) { mem[i] = input[input_ptr + d - i - 1]; } Kernels.celt_fir(input.Slice(input_ptr + d), num, output.Slice(output_ptr + d), len - d, d, mem); for (int i = output_ptr; i < output_ptr + d; i++) { output[i] = 0; } } internal static int LPC_inverse_pred_gain_QA(int[][] A_QA, int order) { int[] array = A_QA[order & 1]; int a = 1073741824; int num2; int num3; for (int num = order - 1; num > 0; num--) { if (array[num] > A_LIMIT || array[num] < -A_LIMIT) { return 0; } num2 = -Inlines.silk_LSHIFT(array[num], 7); num3 = 1073741824 - Inlines.silk_SMMUL(num2, num2); int num4 = 32 - Inlines.silk_CLZ32(Inlines.silk_abs(num3)); int b = Inlines.silk_INVERSE32_varQ(num3, num4 + 30); a = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(a, num3), 2); int[] array2 = array; array = A_QA[num & 1]; for (int i = 0; i < num; i++) { int a2 = array2[i] - Inlines.MUL32_FRAC_Q(array2[num - i - 1], num2, 31); array[i] = Inlines.MUL32_FRAC_Q(a2, b, num4); } } if (array[0] > A_LIMIT || array[0] < -A_LIMIT) { return 0; } num2 = -Inlines.silk_LSHIFT(array[0], 7); num3 = 1073741824 - Inlines.silk_SMMUL(num2, num2); return Inlines.silk_LSHIFT(Inlines.silk_SMMUL(a, num3), 2); } internal static int silk_LPC_inverse_pred_gain(short[] A_Q12, int order) { int[][] array = new int[2][] { new int[order], new int[order] }; int num = 0; int[] array2 = array[order & 1]; for (int i = 0; i < order; i++) { num += A_Q12[i]; array2[i] = Inlines.silk_LSHIFT32(A_Q12[i], 12); } if (num >= 4096) { return 0; } return LPC_inverse_pred_gain_QA(array, order); } } internal static class FindLPC { internal static void silk_find_LPC(SilkChannelEncoder psEncC, short[] NLSF_Q15, short[] x, int minInvGain_Q30) { int[] a_Q = new int[16]; BoxedValueInt boxedValueInt = new BoxedValueInt(); BoxedValueInt boxedValueInt2 = new BoxedValueInt(); int[] a_Q2 = new int[16]; short[] array = new short[16]; short[] array2 = new short[16]; int num = psEncC.subfr_length + psEncC.predictLPCOrder; psEncC.indices.NLSFInterpCoef_Q2 = 4; BurgModified.silk_burg_modified(boxedValueInt, boxedValueInt2, a_Q, x, 0, minInvGain_Q30, num, psEncC.nb_subfr, psEncC.predictLPCOrder); int num2 = boxedValueInt.Val; int num3 = boxedValueInt2.Val; if (psEncC.useInterpolatedNLSFs != 0 && psEncC.first_frame_after_reset == 0 && psEncC.nb_subfr == 4) { BurgModified.silk_burg_modified(boxedValueInt, boxedValueInt2, a_Q2, x, 2 * num, minInvGain_Q30, num, 2, psEncC.predictLPCOrder); int val = boxedValueInt.Val; int val2 = boxedValueInt2.Val; int num4 = val2 - num3; if (num4 >= 0) { if (num4 < 32) { num2 -= Inlines.silk_RSHIFT(val, num4); } } else { num2 = Inlines.silk_RSHIFT(num2, -num4) - val; num3 = val2; } NLSF.silk_A2NLSF(NLSF_Q15, a_Q2, psEncC.predictLPCOrder); short[] array3 = new short[2 * num]; for (int num5 = 3; num5 >= 0; num5--) { Inlines.silk_interpolate(array2, psEncC.prev_NLSFq_Q15, NLSF_Q15, num5, psEncC.predictLPCOrder); NLSF.silk_NLSF2A(array, array2, psEncC.predictLPCOrder); Filters.silk_LPC_analysis_filter(array3, 0, x, 0, array, 0, 2 * num, psEncC.predictLPCOrder); SumSqrShift.silk_sum_sqr_shift(out var energy, out var shift, array3, psEncC.predictLPCOrder, num - psEncC.predictLPCOrder); SumSqrShift.silk_sum_sqr_shift(out var energy2, out var shift2, array3, psEncC.predictLPCOrder + num, num - psEncC.predictLPCOrder); num4 = shift - shift2; int num6; if (num4 >= 0) { energy2 = Inlines.silk_RSHIFT(energy2, num4); num6 = -shift; } else { energy = Inlines.silk_RSHIFT(energy, -num4); num6 = -shift2; } int num7 = Inlines.silk_ADD32(energy, energy2); num4 = num6 - num3; int num8 = ((num4 >= 0) ? ((Inlines.silk_RSHIFT(num7, num4) < num2) ? 1 : 0) : ((-num4 < 32) ? ((num7 < Inlines.silk_RSHIFT(num2, -num4)) ? 1 : 0) : 0)); if (num8 == 1) { num2 = num7; num3 = num6; psEncC.indices.NLSFInterpCoef_Q2 = (sbyte)num5; } } } if (psEncC.indices.NLSFInterpCoef_Q2 == 4) { NLSF.silk_A2NLSF(NLSF_Q15, a_Q, psEncC.predictLPCOrder); } } } internal static class FindLTP { private const int LTP_CORRS_HEAD_ROOM = 2; internal static void silk_find_LTP(short[] b_Q14, int[] WLTP, BoxedValueInt LTPredCodGain_Q7, short[] r_lpc, int[] lag, int[] Wght_Q15, int subfr_length, int nb_subfr, int mem_offset, int[] corr_rshifts) { int[] array = new int[5]; int[] array2 = new int[5]; int[] array3 = new int[4]; int[] array4 = new int[4]; int[] array5 = new int[4]; int[] array6 = new int[5]; int[] array7 = new int[4]; int num = 0; int num2 = 0; int num3 = mem_offset; int num5; int a3; for (int i = 0; i < nb_subfr; i++) { int x_ptr = num3 - (lag[i] + 2); SumSqrShift.silk_sum_sqr_shift(out array7[i], out var shift, r_lpc, num3, subfr_length); int num4 = Inlines.silk_CLZ32(array7[i]); if (num4 < 2) { array7[i] = Inlines.silk_RSHIFT_ROUND(array7[i], 2 - num4); shift += 2 - num4; } corr_rshifts[i] = shift; BoxedValueInt boxedValueInt = new BoxedValueInt(corr_rshifts[i]); CorrelateMatrix.silk_corrMatrix(r_lpc, x_ptr, subfr_length, 5, 2, WLTP, num2, boxedValueInt); corr_rshifts[i] = boxedValueInt.Val; CorrelateMatrix.silk_corrVector(r_lpc, x_ptr, r_lpc, num3, subfr_length, 5, array6, corr_rshifts[i]); if (corr_rshifts[i] > shift) { array7[i] = Inlines.silk_RSHIFT(array7[i], corr_rshifts[i] - shift); } int a = 1; a = Inlines.silk_SMLAWB(a, array7[i], 1092); a = Inlines.silk_SMLAWB(a, Inlines.MatrixGet(WLTP, num2, 0, 0, 5), 1092); a = Inlines.silk_SMLAWB(a, Inlines.MatrixGet(WLTP, num2, 4, 4, 5), 1092); RegularizeCorrelations.silk_regularize_correlations(WLTP, num2, array7, i, a, 5); LinearAlgebra.silk_solve_LDL(WLTP, num2, 5, array6, array); silk_fit_LTP(array, b_Q14, num); array4[i] = ResidualEnergy.silk_residual_energy16_covar(b_Q14, num, WLTP, num2, array6, array7[i], 5, 14); num5 = Inlines.silk_min_int(corr_rshifts[i], 2); int a2 = Inlines.silk_LSHIFT_SAT32(Inlines.silk_SMULWB(array4[i], Wght_Q15[i]), 1 + num5) + Inlines.silk_RSHIFT(Inlines.silk_SMULWB(subfr_length, 655), corr_rshifts[i] - num5); a2 = Inlines.silk_max(a2, 1); a3 = Inlines.silk_DIV32(Inlines.silk_LSHIFT(Wght_Q15[i], 16), a2); a3 = Inlines.silk_RSHIFT(a3, 31 + corr_rshifts[i] - num5 - 26); int num6 = 0; for (int j = num2; j < num2 + 25; j++) { num6 = Inlines.silk_max(WLTP[j], num6); } int num7 = Inlines.silk_CLZ32(num6) - 1 - 3; if (8 + num7 < 31) { a3 = Inlines.silk_min_32(a3, Inlines.silk_LSHIFT(1, 8 + num7)); } Inlines.silk_scale_vector32_Q26_lshift_18(WLTP, num2, a3, 25); array5[i] = Inlines.MatrixGet(WLTP, num2, 2, 2, 5); num3 += subfr_length; num += 5; num2 += 25; } int num8 = 0; for (int i = 0; i < nb_subfr; i++) { num8 = Inlines.silk_max_int(corr_rshifts[i], num8); } if (LTPredCodGain_Q7 != null) { int a4 = 0; int num9 = 0; for (int i = 0; i < nb_subfr; i++) { num9 = Inlines.silk_ADD32(num9, Inlines.silk_RSHIFT(Inlines.silk_ADD32(Inlines.silk_SMULWB(array7[i], Wght_Q15[i]), 1), 1 + (num8 - corr_rshifts[i]))); a4 = Inlines.silk_ADD32(a4, Inlines.silk_RSHIFT(Inlines.silk_ADD32(Inlines.silk_SMULWB(array4[i], Wght_Q15[i]), 1), 1 + (num8 - corr_rshifts[i]))); } a4 = Inlines.silk_max(a4, 1); int inLin = Inlines.silk_DIV32_varQ(num9, a4, 16); LTPredCodGain_Q7.Val = Inlines.silk_SMULBB(3, Inlines.silk_lin2log(inLin) - 2048); } num = 0; for (int i = 0; i < nb_subfr; i++) { array3[i] = 0; for (int j = num; j < num + 5; j++) { array3[i] += b_Q14[j]; } num += 5; } int num10 = 0; int num11 = 0; for (int i = 0; i < nb_subfr; i++) { num10 = Inlines.silk_max_32(num10, Inlines.silk_abs(array3[i])); num11 = Inlines.silk_max_32(num11, 32 - Inlines.silk_CLZ32(array5[i]) + corr_rshifts[i] - num8); } num5 = num11 + 32 - Inlines.silk_CLZ32(num10) - 14; num5 -= 29 + num8; num5 = Inlines.silk_max_int(num5, 0); int num12 = num8 + num5; a3 = Inlines.silk_RSHIFT(262, num8 + num5) + 1; int num13 = 0; for (int i = 0; i < nb_subfr; i++) { a3 = Inlines.silk_ADD32(a3, Inlines.silk_RSHIFT(array5[i], num12 - corr_rshifts[i])); num13 = Inlines.silk_ADD32(num13, Inlines.silk_LSHIFT(Inlines.silk_SMULWW(Inlines.silk_RSHIFT(array5[i], num12 - corr_rshifts[i]), array3[i]), 2)); } int a5 = Inlines.silk_DIV32_varQ(num13, a3, 12); num = 0; for (int i = 0; i < nb_subfr; i++) { a3 = ((2 - corr_rshifts[i] <= 0) ? Inlines.silk_LSHIFT_SAT32(array5[i], corr_rshifts[i] - 2) : Inlines.silk_RSHIFT(array5[i], 2 - corr_rshifts[i])); int a6 = Inlines.silk_MUL(Inlines.silk_DIV32(6710887, Inlines.silk_RSHIFT(6710887, 10) + a3), Inlines.silk_LSHIFT_SAT32(Inlines.silk_SUB_SAT32(a5, Inlines.silk_RSHIFT(array3[i], 2)), 4)); a3 = 0; for (int j = 0; j < 5; j++) { array2[j] = Inlines.silk_max_16(b_Q14[num + j], 1638); a3 += array2[j]; } a3 = Inlines.silk_DIV32(a6, a3); for (int j = 0; j < 5; j++) { b_Q14[num + j] = (short)Inlines.silk_LIMIT_32(b_Q14[num + j] + Inlines.silk_SMULWB(Inlines.silk_LSHIFT_SAT32(a3, 4), array2[j]), -16000, 28000); } num += 5; } } internal static void silk_fit_LTP(int[] LTP_coefs_Q16, Span LTP_coefs_Q14, int LTP_coefs_Q14_ptr) { for (int i = 0; i < 5; i++) { LTP_coefs_Q14[LTP_coefs_Q14_ptr + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(LTP_coefs_Q16[i], 2)); } } } internal static class FindPitchLags { internal static void silk_find_pitch_lags(SilkChannelEncoder psEnc, SilkEncoderControl psEncCtrl, short[] res, short[] x, int x_ptr) { int[] array = new int[17]; short[] rc_Q = new short[16]; int[] array2 = new int[16]; short[] array3 = new short[16]; int num = psEnc.la_pitch + psEnc.frame_length + psEnc.ltp_mem_length; int num2 = x_ptr - psEnc.ltp_mem_length; short[] array4 = new short[psEnc.pitch_LPC_win_length]; int num3 = num2 + num - psEnc.pitch_LPC_win_length; int num4 = 0; ApplySineWindow.silk_apply_sine_window(array4, num4, x, num3, 1, psEnc.la_pitch); num4 += psEnc.la_pitch; num3 += psEnc.la_pitch; Arrays.MemCopy(x, num3, array4, num4, psEnc.pitch_LPC_win_length - Inlines.silk_LSHIFT(psEnc.la_pitch, 1)); num4 += psEnc.pitch_LPC_win_length - Inlines.silk_LSHIFT(psEnc.la_pitch, 1); num3 += psEnc.pitch_LPC_win_length - Inlines.silk_LSHIFT(psEnc.la_pitch, 1); ApplySineWindow.silk_apply_sine_window(array4, num4, x, num3, 2, psEnc.la_pitch); Autocorrelation.silk_autocorr(array, out var _, array4, psEnc.pitch_LPC_win_length, psEnc.pitchEstimationLPCOrder + 1); array[0] = Inlines.silk_SMLAWB(array[0], array[0], 66) + 1; int a = Schur.silk_schur(rc_Q, array, psEnc.pitchEstimationLPCOrder); psEncCtrl.predGain_Q16 = Inlines.silk_DIV32_varQ(array[0], Inlines.silk_max_int(a, 1), 16); K2A.silk_k2a(array2, rc_Q, psEnc.pitchEstimationLPCOrder); for (int i = 0; i < psEnc.pitchEstimationLPCOrder; i++) { array3[i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(array2[i], 12)); } BWExpander.silk_bwexpander(array3, psEnc.pitchEstimationLPCOrder, 64881); Filters.silk_LPC_analysis_filter(res, 0, x, num2, array3, 0, num, psEnc.pitchEstimationLPCOrder); if (psEnc.indices.signalType != 0 && psEnc.first_frame_after_reset == 0) { int a2 = 4915; a2 = Inlines.silk_SMLABB(a2, -32, psEnc.pitchEstimationLPCOrder); a2 = Inlines.silk_SMLAWB(a2, -209714, psEnc.speech_activity_Q8); a2 = Inlines.silk_SMLABB(a2, -1228, Inlines.silk_RSHIFT(psEnc.prevSignalType, 1)); a2 = Inlines.silk_SMLAWB(a2, -1637, psEnc.input_tilt_Q15); a2 = Inlines.silk_SAT16(a2); BoxedValueShort boxedValueShort = new BoxedValueShort(psEnc.indices.lagIndex); BoxedValueSbyte boxedValueSbyte = new BoxedValueSbyte(psEnc.indices.contourIndex); BoxedValueInt boxedValueInt = new BoxedValueInt(psEnc.LTPCorr_Q15); if (PitchAnalysisCore.silk_pitch_analysis_core(res, psEncCtrl.pitchL, boxedValueShort, boxedValueSbyte, boxedValueInt, psEnc.prevLag, psEnc.pitchEstimationThreshold_Q16, a2, psEnc.fs_kHz, psEnc.pitchEstimationComplexity, psEnc.nb_subfr) == 0) { psEnc.indices.signalType = 2; } else { psEnc.indices.signalType = 1; } psEnc.indices.lagIndex = boxedValueShort.Val; psEnc.indices.contourIndex = boxedValueSbyte.Val; psEnc.LTPCorr_Q15 = boxedValueInt.Val; } else { Arrays.MemSetInt(psEncCtrl.pitchL, 0, 4); psEnc.indices.lagIndex = 0; psEnc.indices.contourIndex = 0; psEnc.LTPCorr_Q15 = 0; } } } internal static class FindPredCoefs { internal static void silk_find_pred_coefs(SilkChannelEncoder psEnc, SilkEncoderControl psEncCtrl, short[] res_pitch, short[] x, int x_ptr, int condCoding) { int[] array = new int[4]; int[] array2 = new int[4]; int[] array3 = new int[4]; short[] array4 = new short[16]; int[] corr_rshifts = new int[4]; int num = 33554431; for (int i = 0; i < psEnc.nb_subfr; i++) { num = Inlines.silk_min(num, psEncCtrl.Gains_Q16[i]); } for (int i = 0; i < psEnc.nb_subfr; i++) { array[i] = Inlines.silk_DIV32_varQ(num, psEncCtrl.Gains_Q16[i], 14); array[i] = Inlines.silk_max(array[i], 363); int a = Inlines.silk_SMULWB(array[i], array[i]); array3[i] = Inlines.silk_RSHIFT(a, 1); array2[i] = Inlines.silk_DIV32(65536, array[i]); } short[] array5 = new short[psEnc.nb_subfr * psEnc.predictLPCOrder + psEnc.frame_length]; if (psEnc.indices.signalType == 2) { int[] array6 = new int[psEnc.nb_subfr * 5 * 5]; BoxedValueInt boxedValueInt = new BoxedValueInt(psEncCtrl.LTPredCodGain_Q7); FindLTP.silk_find_LTP(psEncCtrl.LTPCoef_Q14, array6, boxedValueInt, res_pitch, psEncCtrl.pitchL, array3, psEnc.subfr_length, psEnc.nb_subfr, psEnc.ltp_mem_length, corr_rshifts); psEncCtrl.LTPredCodGain_Q7 = boxedValueInt.Val; BoxedValueSbyte boxedValueSbyte = new BoxedValueSbyte(psEnc.indices.PERIndex); BoxedValueInt boxedValueInt2 = new BoxedValueInt(psEnc.sum_log_gain_Q7); QuantizeLTPGains.silk_quant_LTP_gains(psEncCtrl.LTPCoef_Q14, psEnc.indices.LTPIndex, boxedValueSbyte, boxedValueInt2, array6, psEnc.mu_LTP_Q9, psEnc.LTPQuantLowComplexity, psEnc.nb_subfr); psEnc.indices.PERIndex = boxedValueSbyte.Val; psEnc.sum_log_gain_Q7 = boxedValueInt2.Val; LTPScaleControl.silk_LTP_scale_ctrl(psEnc, psEncCtrl, condCoding); LTPAnalysisFilter.silk_LTP_analysis_filter(array5, x, x_ptr - psEnc.predictLPCOrder, psEncCtrl.LTPCoef_Q14, psEncCtrl.pitchL, array, psEnc.subfr_length, psEnc.nb_subfr, psEnc.predictLPCOrder); } else { int num2 = x_ptr - psEnc.predictLPCOrder; int num3 = 0; for (int i = 0; i < psEnc.nb_subfr; i++) { Inlines.silk_scale_copy_vector16(array5, num3, x, num2, array[i], psEnc.subfr_length + psEnc.predictLPCOrder); num3 += psEnc.subfr_length + psEnc.predictLPCOrder; num2 += psEnc.subfr_length; } Arrays.MemSetShort(psEncCtrl.LTPCoef_Q14, 0, psEnc.nb_subfr * 5); psEncCtrl.LTPredCodGain_Q7 = 0; psEnc.sum_log_gain_Q7 = 0; } int minInvGain_Q; if (psEnc.first_frame_after_reset != 0) { minInvGain_Q = 10737418; } else { minInvGain_Q = Inlines.silk_log2lin(Inlines.silk_SMLAWB(2048, psEncCtrl.LTPredCodGain_Q7, 21845)); minInvGain_Q = Inlines.silk_DIV32_varQ(minInvGain_Q, Inlines.silk_SMULWW(10000, Inlines.silk_SMLAWB(65536, 196608, psEncCtrl.coding_quality_Q14)), 14); } FindLPC.silk_find_LPC(psEnc, array4, array5, minInvGain_Q); NLSF.silk_process_NLSFs(psEnc, psEncCtrl.PredCoef_Q12, array4, psEnc.prev_NLSFq_Q15); ResidualEnergy.silk_residual_energy(psEncCtrl.ResNrg, psEncCtrl.ResNrgQ, array5, psEncCtrl.PredCoef_Q12, array2, psEnc.subfr_length, psEnc.nb_subfr, psEnc.predictLPCOrder); Arrays.MemCopy(array4, 0, psEnc.prev_NLSFq_Q15, 0, 16); } } internal static class GainQuantization { private static readonly int OFFSET = 2090; private static readonly int SCALE_Q16 = 2251; private static readonly int INV_SCALE_Q16 = 1907825; internal static void silk_gains_quant(sbyte[] ind, int[] gain_Q16, BoxedValueSbyte prev_ind, int conditional, int nb_subfr) { for (int i = 0; i < nb_subfr; i++) { ind[i] = (sbyte)Inlines.silk_SMULWB(SCALE_Q16, Inlines.silk_lin2log(gain_Q16[i]) - OFFSET); if (ind[i] < prev_ind.Val) { ind[i]++; } ind[i] = (sbyte)Inlines.silk_LIMIT_int(ind[i], 0, 63); if (i == 0 && conditional == 0) { ind[i] = (sbyte)Inlines.silk_LIMIT_int(ind[i], prev_ind.Val + -4, 63); prev_ind.Val = ind[i]; } else { ind[i] -= prev_ind.Val; int num = 8 + prev_ind.Val; if (ind[i] > num) { ind[i] = (sbyte)(num + Inlines.silk_RSHIFT(ind[i] - num + 1, 1)); } ind[i] = (sbyte)Inlines.silk_LIMIT_int(ind[i], -4, 36); if (ind[i] > num) { prev_ind.Val += (sbyte)(Inlines.silk_LSHIFT(ind[i], 1) - num); } else { prev_ind.Val += ind[i]; } ind[i] -= -4; } gain_Q16[i] = Inlines.silk_log2lin(Inlines.silk_min_32(Inlines.silk_SMULWB(INV_SCALE_Q16, prev_ind.Val) + OFFSET, 3967)); } } internal static void silk_gains_dequant(int[] gain_Q16, sbyte[] ind, BoxedValueSbyte prev_ind, int conditional, int nb_subfr) { for (int i = 0; i < nb_subfr; i++) { if (i == 0 && conditional == 0) { prev_ind.Val = (sbyte)Inlines.silk_max_int(ind[i], prev_ind.Val - 16); } else { int num = ind[i] + -4; int num2 = 8 + prev_ind.Val; if (num > num2) { prev_ind.Val += (sbyte)(Inlines.silk_LSHIFT(num, 1) - num2); } else { prev_ind.Val += (sbyte)num; } } prev_ind.Val = (sbyte)Inlines.silk_LIMIT_int(prev_ind.Val, 0, 63); gain_Q16[i] = Inlines.silk_log2lin(Inlines.silk_min_32(Inlines.silk_SMULWB(INV_SCALE_Q16, prev_ind.Val) + OFFSET, 3967)); } } internal static int silk_gains_ID(sbyte[] ind, int nb_subfr) { int num = 0; for (int i = 0; i < nb_subfr; i++) { num = Inlines.silk_ADD_LSHIFT32(ind[i], num, 8); } return num; } } internal static class HPVariableCutoff { internal static void silk_HP_variable_cutoff(SilkChannelEncoder[] state_Fxx) { SilkChannelEncoder silkChannelEncoder = state_Fxx[0]; if (silkChannelEncoder.prevSignalType == 2) { int num = Inlines.silk_lin2log(Inlines.silk_DIV32_16(Inlines.silk_LSHIFT(Inlines.silk_MUL(silkChannelEncoder.fs_kHz, 1000), 16), silkChannelEncoder.prevLag)) - 2048; int num2 = silkChannelEncoder.input_quality_bands_Q15[0]; num = Inlines.silk_SMLAWB(num, Inlines.silk_SMULWB(Inlines.silk_LSHIFT(-num2, 2), num2), num - (Inlines.silk_lin2log(3932160) - 2048)); int num3 = num - Inlines.silk_RSHIFT(silkChannelEncoder.variable_HP_smth1_Q15, 8); if (num3 < 0) { num3 = Inlines.silk_MUL(num3, 3); } num3 = Inlines.silk_LIMIT_32(num3, -51, 51); silkChannelEncoder.variable_HP_smth1_Q15 = Inlines.silk_SMLAWB(silkChannelEncoder.variable_HP_smth1_Q15, Inlines.silk_SMULBB(silkChannelEncoder.speech_activity_Q8, num3), 6554); silkChannelEncoder.variable_HP_smth1_Q15 = Inlines.silk_LIMIT_32(silkChannelEncoder.variable_HP_smth1_Q15, Inlines.silk_LSHIFT(Inlines.silk_lin2log(60), 8), Inlines.silk_LSHIFT(Inlines.silk_lin2log(100), 8)); } } } internal static class K2A { internal static void silk_k2a(int[] A_Q24, short[] rc_Q15, int order) { int[] array = new int[16]; for (int i = 0; i < order; i++) { for (int j = 0; j < i; j++) { array[j] = A_Q24[j]; } for (int j = 0; j < i; j++) { A_Q24[j] = Inlines.silk_SMLAWB(A_Q24[j], Inlines.silk_LSHIFT(array[i - j - 1], 1), rc_Q15[i]); } A_Q24[i] = -Inlines.silk_LSHIFT(rc_Q15[i], 9); } } internal static void silk_k2a_Q16(int[] A_Q24, int[] rc_Q16, int order) { int[] array = new int[16]; for (int i = 0; i < order; i++) { for (int j = 0; j < i; j++) { array[j] = A_Q24[j]; } for (int j = 0; j < i; j++) { A_Q24[j] = Inlines.silk_SMLAWW(A_Q24[j], array[i - j - 1], rc_Q16[i]); } A_Q24[i] = -Inlines.silk_LSHIFT(rc_Q16[i], 8); } } } internal static class LinearAlgebra { internal static void silk_solve_LDL(int[] A, int A_ptr, int M, int[] b, int[] x_Q16) { int[] l_Q = new int[M * M]; int[] array = new int[16]; int[] inv_D = new int[32]; silk_LDL_factorize(A, A_ptr, M, l_Q, inv_D); silk_LS_SolveFirst(l_Q, M, b, array); silk_LS_divide_Q16(array, inv_D, M); silk_LS_SolveLast(l_Q, M, array, x_Q16); } private static void silk_LDL_factorize(int[] A, int A_ptr, int M, int[] L_Q16, int[] inv_D) { int[] array = new int[M]; int[] array2 = new int[M]; int num = 1; int num2 = Inlines.silk_max_32(Inlines.silk_SMMUL(Inlines.silk_ADD_SAT32(A[A_ptr], A[A_ptr + Inlines.silk_SMULBB(M, M) - 1]), 21475), 512); for (int i = 0; i < M; i++) { if (num != 1) { break; } num = 0; for (int j = 0; j < M; j++) { int[] array3 = L_Q16; int num3 = Inlines.MatrixGetPointer(j, 0, M); int num4 = 0; for (int k = 0; k < j; k++) { array[k] = Inlines.silk_SMULWW(array2[k], array3[num3 + k]); num4 = Inlines.silk_SMLAWW(num4, array[k], array3[num3 + k]); } num4 = Inlines.silk_SUB32(Inlines.MatrixGet(A, A_ptr, j, j, M), num4); if (num4 < num2) { num4 = Inlines.silk_SUB32(Inlines.silk_SMULBB(i + 1, num2), num4); for (int k = 0; k < M; k++) { Inlines.MatrixSet(A, A_ptr, k, k, M, Inlines.silk_ADD32(Inlines.MatrixGet(A, A_ptr, k, k, M), num4)); } num = 1; break; } array2[j] = num4; int num5 = Inlines.silk_INVERSE32_varQ(num4, 36); int b = Inlines.silk_LSHIFT(num5, 4); int num6 = Inlines.silk_SMULWW(Inlines.silk_SUB32(16777216, Inlines.silk_SMULWW(num4, b)), b); inv_D[j * 2] = num5; inv_D[j * 2 + 1] = num6; Inlines.MatrixSet(L_Q16, j, j, M, 65536); array3 = A; num3 = Inlines.MatrixGetPointer(j, 0, M) + A_ptr; int num7 = Inlines.MatrixGetPointer(j + 1, 0, M); for (int k = j + 1; k < M; k++) { num4 = 0; for (int l = 0; l < j; l++) { num4 = Inlines.silk_SMLAWW(num4, array[l], L_Q16[num7 + l]); } num4 = Inlines.silk_SUB32(array3[num3 + k], num4); Inlines.MatrixSet(L_Q16, k, j, M, Inlines.silk_ADD32(Inlines.silk_SMMUL(num4, num6), Inlines.silk_RSHIFT(Inlines.silk_SMULWW(num4, num5), 4))); num7 += M; } } } } private static void silk_LS_divide_Q16(int[] T, int[] inv_D, int M) { for (int i = 0; i < M; i++) { int b = inv_D[i * 2]; int b2 = inv_D[i * 2 + 1]; int a = T[i]; T[i] = Inlines.silk_ADD32(Inlines.silk_SMMUL(a, b2), Inlines.silk_RSHIFT(Inlines.silk_SMULWW(a, b), 4)); } } private static void silk_LS_SolveFirst(int[] L_Q16, int M, int[] b, int[] x_Q16) { for (int i = 0; i < M; i++) { int num = Inlines.MatrixGetPointer(i, 0, M); int num2 = 0; for (int j = 0; j < i; j++) { num2 = Inlines.silk_SMLAWW(num2, L_Q16[num + j], x_Q16[j]); } x_Q16[i] = Inlines.silk_SUB32(b[i], num2); } } private static void silk_LS_SolveLast(int[] L_Q16, int M, int[] b, int[] x_Q16) { for (int num = M - 1; num >= 0; num--) { int num2 = Inlines.MatrixGetPointer(0, num, M); int num3 = 0; for (int num4 = M - 1; num4 > num; num4--) { num3 = Inlines.silk_SMLAWW(num3, L_Q16[num2 + Inlines.silk_SMULBB(num4, M)], x_Q16[num4]); } x_Q16[num] = Inlines.silk_SUB32(b[num], num3); } } } internal static class LPCInversePredGain { private const float RC_THRESHOLD = 0.9999f; private const int QA = 24; private static readonly int A_LIMIT = 16773022; internal static int LPC_inverse_pred_gain_QA(int[][] A_QA, int order) { int[] array = A_QA[order & 1]; int a = 1073741824; int num2; int num3; for (int num = order - 1; num > 0; num--) { if (array[num] > A_LIMIT || array[num] < -A_LIMIT) { return 0; } num2 = -Inlines.silk_LSHIFT(array[num], 7); num3 = 1073741824 - Inlines.silk_SMMUL(num2, num2); int num4 = 32 - Inlines.silk_CLZ32(Inlines.silk_abs(num3)); int b = Inlines.silk_INVERSE32_varQ(num3, num4 + 30); a = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(a, num3), 2); int[] array2 = array; array = A_QA[num & 1]; for (int i = 0; i < num; i++) { int a2 = array2[i] - Inlines.MUL32_FRAC_Q(array2[num - i - 1], num2, 31); array[i] = Inlines.MUL32_FRAC_Q(a2, b, num4); } } if (array[0] > A_LIMIT || array[0] < -A_LIMIT) { return 0; } num2 = -Inlines.silk_LSHIFT(array[0], 7); num3 = 1073741824 - Inlines.silk_SMMUL(num2, num2); return Inlines.silk_LSHIFT(Inlines.silk_SMMUL(a, num3), 2); } internal static int silk_LPC_inverse_pred_gain(short[] A_Q12, int order) { int[][] array = Arrays.InitTwoDimensionalArray(2, 16); int num = 0; int[] array2 = array[order & 1]; for (int i = 0; i < order; i++) { num += A_Q12[i]; array2[i] = Inlines.silk_LSHIFT32(A_Q12[i], 12); } if (num >= 4096) { return 0; } return LPC_inverse_pred_gain_QA(array, order); } internal static int silk_LPC_inverse_pred_gain_Q24(int[] A_Q24, int order) { int[][] array = Arrays.InitTwoDimensionalArray(2, 16); int[] array2 = array[order & 1]; for (int i = 0; i < order; i++) { array2[i] = Inlines.silk_RSHIFT32(A_Q24[i], 0); } return LPC_inverse_pred_gain_QA(array, order); } } internal static class LTPAnalysisFilter { internal static void silk_LTP_analysis_filter(short[] LTP_res, short[] x, int x_ptr, short[] LTPCoef_Q14, int[] pitchL, int[] invGains_Q16, int subfr_length, int nb_subfr, int pre_length) { short[] array = new short[5]; int num = x_ptr; int num2 = 0; for (int i = 0; i < nb_subfr; i++) { int num3 = num - pitchL[i]; array[0] = LTPCoef_Q14[i * 5]; array[1] = LTPCoef_Q14[i * 5 + 1]; array[2] = LTPCoef_Q14[i * 5 + 2]; array[3] = LTPCoef_Q14[i * 5 + 3]; array[4] = LTPCoef_Q14[i * 5 + 4]; for (int j = 0; j < subfr_length + pre_length; j++) { int num4 = num2 + j; LTP_res[num4] = x[num + j]; int a = Inlines.silk_SMULBB(x[num3 + 2], array[0]); a = Inlines.silk_SMLABB_ovflw(a, x[num3 + 1], array[1]); a = Inlines.silk_SMLABB_ovflw(a, x[num3], array[2]); a = Inlines.silk_SMLABB_ovflw(a, x[num3 - 1], array[3]); a = Inlines.silk_SMLABB_ovflw(a, x[num3 - 2], array[4]); a = Inlines.silk_RSHIFT_ROUND(a, 14); LTP_res[num4] = (short)Inlines.silk_SAT16(x[num + j] - a); LTP_res[num4] = (short)Inlines.silk_SMULWB(invGains_Q16[i], LTP_res[num4]); num3++; } num2 += subfr_length + pre_length; num += subfr_length; } } } internal static class LTPScaleControl { internal static void silk_LTP_scale_ctrl(SilkChannelEncoder psEnc, SilkEncoderControl psEncCtrl, int condCoding) { if (condCoding == 0) { int a = psEnc.PacketLoss_perc + psEnc.nFramesPerPacket; psEnc.indices.LTP_scaleIndex = (sbyte)Inlines.silk_LIMIT(Inlines.silk_SMULWB(Inlines.silk_SMULBB(a, psEncCtrl.LTPredCodGain_Q7), 51), 0, 2); } else { psEnc.indices.LTP_scaleIndex = 0; } psEncCtrl.LTP_scale_Q14 = Tables.silk_LTPScales_table_Q14[psEnc.indices.LTP_scaleIndex]; } } internal static class NLSF { private const int MAX_LPC_ORDER = 16; private const int MAX_STABILIZE_LOOPS = 20; private const int QA = 16; private const int BIN_DIV_STEPS_A2NLSF = 3; private const int MAX_ITERATIONS_A2NLSF = 30; private static readonly byte[] ordering16 = new byte[16] { 0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1 }; private static readonly byte[] ordering10 = new byte[10] { 0, 9, 6, 3, 4, 5, 8, 1, 2, 7 }; internal static void silk_NLSF_VQ(int[] err_Q26, short[] in_Q15, byte[] pCB_Q8, int K, int LPC_order) { int num = 0; for (int i = 0; i < K; i++) { int num2 = 0; for (int j = 0; j < LPC_order; j += 2) { int num3 = Inlines.silk_SUB_LSHIFT32(in_Q15[j], pCB_Q8[num++], 7); int a = Inlines.silk_SMULBB(num3, num3); num3 = Inlines.silk_SUB_LSHIFT32(in_Q15[j + 1], pCB_Q8[num++], 7); a = Inlines.silk_SMLABB(a, num3, num3); num2 = Inlines.silk_ADD_RSHIFT32(num2, a, 4); } err_Q26[i] = num2; } } internal static void silk_NLSF_VQ_weights_laroia(Span pNLSFW_Q_OUT, Span pNLSF_Q15, int D) { int b = Inlines.silk_max_int(pNLSF_Q15[0], 1); b = Inlines.silk_DIV32(131072, b); int b2 = Inlines.silk_max_int(pNLSF_Q15[1] - pNLSF_Q15[0], 1); b2 = Inlines.silk_DIV32(131072, b2); pNLSFW_Q_OUT[0] = (short)Inlines.silk_min_int(b + b2, 32767); for (int i = 1; i < D - 1; i += 2) { b = Inlines.silk_max_int(pNLSF_Q15[i + 1] - pNLSF_Q15[i], 1); b = Inlines.silk_DIV32(131072, b); pNLSFW_Q_OUT[i] = (short)Inlines.silk_min_int(b + b2, 32767); b2 = Inlines.silk_max_int(pNLSF_Q15[i + 2] - pNLSF_Q15[i + 1], 1); b2 = Inlines.silk_DIV32(131072, b2); pNLSFW_Q_OUT[i + 1] = (short)Inlines.silk_min_int(b + b2, 32767); } b = Inlines.silk_max_int(32768 - pNLSF_Q15[D - 1], 1); b = Inlines.silk_DIV32(131072, b); pNLSFW_Q_OUT[D - 1] = (short)Inlines.silk_min_int(b + b2, 32767); } internal static void silk_NLSF_residual_dequant(Span x_Q10, Span indices, Span pred_coef_Q8, int quant_step_size_Q16, short order) { short num = 0; for (int num2 = order - 1; num2 >= 0; num2--) { int a = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(num, pred_coef_Q8[num2]), 8); num = Inlines.silk_LSHIFT16(indices[num2], 10); if (num > 0) { num = Inlines.silk_SUB16(num, 102); } else if (num < 0) { num = Inlines.silk_ADD16(num, 102); } num = (short)Inlines.silk_SMLAWB(a, num, quant_step_size_Q16); x_Q10[num2] = num; } } internal static void silk_NLSF_unpack(Span ec_ix, Span pred_Q8, NLSFCodebook psNLSF_CB, int CB1_index) { byte[] ec_sel = psNLSF_CB.ec_sel; int num = CB1_index * psNLSF_CB.order / 2; for (int i = 0; i < psNLSF_CB.order; i += 2) { byte b = ec_sel[num]; num++; ec_ix[i] = (short)Inlines.silk_SMULBB(Inlines.silk_RSHIFT(b, 1) & 7, 9); pred_Q8[i] = psNLSF_CB.pred_Q8[i + (b & 1) * (psNLSF_CB.order - 1)]; ec_ix[i + 1] = (short)Inlines.silk_SMULBB(Inlines.silk_RSHIFT(b, 5) & 7, 9); pred_Q8[i + 1] = psNLSF_CB.pred_Q8[i + (Inlines.silk_RSHIFT(b, 4) & 1) * (psNLSF_CB.order - 1) + 1]; } } internal static void silk_NLSF_stabilize(short[] NLSF_Q15, short[] NDeltaMin_Q15, int L) { int num = 0; int i; for (i = 0; i < 20; i++) { int num2 = NLSF_Q15[0] - NDeltaMin_Q15[0]; num = 0; int num3; for (int j = 1; j <= L - 1; j++) { num3 = NLSF_Q15[j] - (NLSF_Q15[j - 1] + NDeltaMin_Q15[j]); if (num3 < num2) { num2 = num3; num = j; } } num3 = 32768 - (NLSF_Q15[L - 1] + NDeltaMin_Q15[L]); if (num3 < num2) { num2 = num3; num = L; } if (num2 >= 0) { return; } if (num == 0) { NLSF_Q15[0] = NDeltaMin_Q15[0]; continue; } if (num == L) { NLSF_Q15[L - 1] = (short)(32768 - NDeltaMin_Q15[L]); continue; } int num4 = 0; for (int k = 0; k < num; k++) { num4 += NDeltaMin_Q15[k]; } num4 += Inlines.silk_RSHIFT(NDeltaMin_Q15[num], 1); int num5 = 32768; for (int k = L; k > num; k--) { num5 -= NDeltaMin_Q15[k]; } num5 -= Inlines.silk_RSHIFT(NDeltaMin_Q15[num], 1); short num6 = (short)Inlines.silk_LIMIT_32(Inlines.silk_RSHIFT_ROUND(NLSF_Q15[num - 1] + NLSF_Q15[num], 1), num4, num5); NLSF_Q15[num - 1] = (short)(num6 - Inlines.silk_RSHIFT(NDeltaMin_Q15[num], 1)); NLSF_Q15[num] = (short)(NLSF_Q15[num - 1] + NDeltaMin_Q15[num]); } if (i == 20) { Sort.silk_insertion_sort_increasing_all_values_int16(NLSF_Q15, L); NLSF_Q15[0] = (short)Inlines.silk_max_int(NLSF_Q15[0], NDeltaMin_Q15[0]); for (int j = 1; j < L; j++) { NLSF_Q15[j] = (short)Inlines.silk_max_int(NLSF_Q15[j], NLSF_Q15[j - 1] + NDeltaMin_Q15[j]); } NLSF_Q15[L - 1] = (short)Inlines.silk_min_int(NLSF_Q15[L - 1], 32768 - NDeltaMin_Q15[L]); for (int j = L - 2; j >= 0; j--) { NLSF_Q15[j] = (short)Inlines.silk_min_int(NLSF_Q15[j], NLSF_Q15[j + 1] - NDeltaMin_Q15[j + 1]); } } } internal static void silk_NLSF_decode(short[] pNLSF_Q15, sbyte[] NLSFIndices, NLSFCodebook psNLSF_CB) { Span span = stackalloc byte[16]; Span ec_ix = stackalloc short[16]; Span x_Q = stackalloc short[16]; Span pNLSFW_Q_OUT = stackalloc short[16]; byte[] cB1_NLSF_Q = psNLSF_CB.CB1_NLSF_Q8; int num = NLSFIndices[0] * psNLSF_CB.order; for (int i = 0; i < psNLSF_CB.order; i++) { pNLSF_Q15[i] = Inlines.silk_LSHIFT16(cB1_NLSF_Q[num + i], 7); } silk_NLSF_unpack(ec_ix, span, psNLSF_CB, NLSFIndices[0]); silk_NLSF_residual_dequant(x_Q, NLSFIndices.AsSpan().Slice(1), span, psNLSF_CB.quantStepSize_Q16, psNLSF_CB.order); silk_NLSF_VQ_weights_laroia(pNLSFW_Q_OUT, pNLSF_Q15, psNLSF_CB.order); for (int i = 0; i < psNLSF_CB.order; i++) { int num2 = Inlines.silk_SQRT_APPROX(Inlines.silk_LSHIFT(pNLSFW_Q_OUT[i], 16)); int a = Inlines.silk_ADD32(pNLSF_Q15[i], Inlines.silk_DIV32_16(Inlines.silk_LSHIFT(x_Q[i], 14), (short)num2)); pNLSF_Q15[i] = (short)Inlines.silk_LIMIT(a, 0, 32767); } silk_NLSF_stabilize(pNLSF_Q15, psNLSF_CB.deltaMin_Q15, psNLSF_CB.order); } internal static int silk_NLSF_del_dec_quant(sbyte[] indices, Span x_Q10, Span w_Q5, Span pred_coef_Q8, Span ec_ix, byte[] ec_rates_Q5, int quant_step_size_Q16, short inv_quant_step_size_Q6, int mu_Q20, short order) { Span span = stackalloc int[4]; sbyte[][] array = new sbyte[4][]; int i; for (i = 0; i < 4; i++) { array[i] = new sbyte[16]; } Span span2 = stackalloc short[8]; Span span3 = stackalloc int[8]; Span span4 = stackalloc int[4]; Span span5 = stackalloc int[4]; Span span6 = stackalloc int[20]; Span span7 = stackalloc int[20]; for (i = -10; i <= 9; i++) { int num = Inlines.silk_LSHIFT(i, 10); int num2 = Inlines.silk_ADD16((short)num, 1024); if (i > 0) { num = Inlines.silk_SUB16((short)num, 102); num2 = Inlines.silk_SUB16((short)num2, 102); } else { switch (i) { case 0: num2 = Inlines.silk_SUB16((short)num2, 102); break; case -1: num = Inlines.silk_ADD16((short)num, 102); break; default: num = Inlines.silk_ADD16((short)num, 102); num2 = Inlines.silk_ADD16((short)num2, 102); break; } } span6[i + 10] = Inlines.silk_SMULWB(num, quant_step_size_Q16); span7[i + 10] = Inlines.silk_SMULWB(num2, quant_step_size_Q16); } int num3 = 1; span3[0] = 0; span2[0] = 0; i = order - 1; int a2; while (true) { int a = Inlines.silk_LSHIFT(pred_coef_Q8[i], 8); int num4 = x_Q10[i]; for (int j = 0; j < num3; j++) { int num5 = Inlines.silk_SMULWB(a, span2[j]); int b = Inlines.silk_SUB16((short)num4, (short)num5); a2 = Inlines.silk_SMULWB(inv_quant_step_size_Q6, b); a2 = Inlines.silk_LIMIT(a2, -10, 9); array[j][i] = (sbyte)a2; int num6 = ec_ix[i] + a2; int num = span6[a2 + 10]; int num2 = span7[a2 + 10]; num = Inlines.silk_ADD16((short)num, (short)num5); num2 = Inlines.silk_ADD16((short)num2, (short)num5); span2[j] = (short)num; span2[j + num3] = (short)num2; int num7; int c; if (a2 + 1 >= 4) { if (a2 + 1 == 4) { num7 = ec_rates_Q5[num6 + 4]; c = 280; } else { num7 = Inlines.silk_SMLABB(108, 43, a2); c = Inlines.silk_ADD16((short)num7, 43); } } else if (a2 <= -4) { if (a2 == -4) { num7 = 280; c = ec_rates_Q5[num6 + 1 + 4]; } else { num7 = Inlines.silk_SMLABB(108, -43, a2); c = Inlines.silk_SUB16((short)num7, 43); } } else { num7 = ec_rates_Q5[num6 + 4]; c = ec_rates_Q5[num6 + 1 + 4]; } int a3 = span3[j]; int num8 = Inlines.silk_SUB16((short)num4, (short)num); span3[j] = Inlines.silk_SMLABB(Inlines.silk_MLA(a3, Inlines.silk_SMULBB(num8, num8), w_Q5[i]), mu_Q20, num7); num8 = Inlines.silk_SUB16((short)num4, (short)num2); span3[j + num3] = Inlines.silk_SMLABB(Inlines.silk_MLA(a3, Inlines.silk_SMULBB(num8, num8), w_Q5[i]), mu_Q20, c); } if (num3 <= 2) { for (int j = 0; j < num3; j++) { array[j + num3][i] = (sbyte)(array[j][i] + 1); } num3 = Inlines.silk_LSHIFT(num3, 1); for (int j = num3; j < 4; j++) { array[j][i] = array[j - num3][i]; } } else { if (i <= 0) { break; } for (int j = 0; j < 4; j++) { if (span3[j] > span3[j + 4]) { span5[j] = span3[j]; span4[j] = span3[j + 4]; span3[j] = span4[j]; span3[j + 4] = span5[j]; int num = span2[j]; span2[j] = span2[j + 4]; span2[j + 4] = (short)num; span[j] = j + 4; } else { span4[j] = span3[j]; span5[j] = span3[j + 4]; span[j] = j; } } while (true) { int num9 = int.MaxValue; int num10 = 0; int num11 = 0; int num12 = 0; for (int j = 0; j < 4; j++) { if (num9 > span5[j]) { num9 = span5[j]; num11 = j; } if (num10 < span4[j]) { num10 = span4[j]; num12 = j; } } if (num9 >= num10) { break; } span[num12] = span[num11] ^ 4; span3[num12] = span3[num11 + 4]; span2[num12] = span2[num11 + 4]; span4[num12] = 0; span5[num11] = int.MaxValue; Buffer.BlockCopy(array[num11], 0, array[num12], 0, order); } for (int j = 0; j < 4; j++) { sbyte b2 = (sbyte)Inlines.silk_RSHIFT(span[j], 2); array[j][i] += b2; } } i--; } a2 = 0; int num13 = int.MaxValue; for (int j = 0; j < 8; j++) { if (num13 > span3[j]) { num13 = span3[j]; a2 = j; } } for (int j = 0; j < order; j++) { indices[j] = array[a2 & 3][j]; } indices[0] = (sbyte)(indices[0] + Inlines.silk_RSHIFT(a2, 2)); return num13; } internal static int silk_NLSF_encode(sbyte[] NLSFIndices, short[] pNLSF_Q15, NLSFCodebook psNLSF_CB, short[] pW_QW, int NLSF_mu_Q20, int nSurvivors, int signalType) { Span span = stackalloc short[16]; Span x_Q = stackalloc short[16]; Span pNLSF_Q16 = stackalloc short[16]; Span pNLSFW_Q_OUT = stackalloc short[16]; Span w_Q = stackalloc short[16]; Span span2 = stackalloc byte[16]; Span ec_ix = stackalloc short[16]; byte[] cB1_NLSF_Q = psNLSF_CB.CB1_NLSF_Q8; silk_NLSF_stabilize(pNLSF_Q15, psNLSF_CB.deltaMin_Q15, psNLSF_CB.order); int[] array = new int[psNLSF_CB.nVectors]; silk_NLSF_VQ(array, pNLSF_Q15, psNLSF_CB.CB1_NLSF_Q8, psNLSF_CB.nVectors, psNLSF_CB.order); int[] array2 = new int[nSurvivors]; Sort.silk_insertion_sort_increasing(array, array2, psNLSF_CB.nVectors, nSurvivors); int[] array3 = new int[nSurvivors]; sbyte[][] array4 = Arrays.InitTwoDimensionalArray(nSurvivors, 16); for (int i = 0; i < nSurvivors; i++) { int num = array2[i]; int num2 = num * psNLSF_CB.order; for (int j = 0; j < psNLSF_CB.order; j++) { pNLSF_Q16[j] = Inlines.silk_LSHIFT16(cB1_NLSF_Q[num2 + j], 7); span[j] = (short)(pNLSF_Q15[j] - pNLSF_Q16[j]); } silk_NLSF_VQ_weights_laroia(pNLSFW_Q_OUT, pNLSF_Q16, psNLSF_CB.order); for (int j = 0; j < psNLSF_CB.order; j++) { int b = Inlines.silk_SQRT_APPROX(Inlines.silk_LSHIFT(pNLSFW_Q_OUT[j], 16)); x_Q[j] = (short)Inlines.silk_RSHIFT(Inlines.silk_SMULBB(span[j], b), 14); } for (int j = 0; j < psNLSF_CB.order; j++) { w_Q[j] = (short)Inlines.silk_DIV32_16(Inlines.silk_LSHIFT(pW_QW[j], 5), pNLSFW_Q_OUT[j]); } silk_NLSF_unpack(ec_ix, span2, psNLSF_CB, num); array3[i] = silk_NLSF_del_dec_quant(array4[i], x_Q, w_Q, span2, ec_ix, psNLSF_CB.ec_Rates_Q5, psNLSF_CB.quantStepSize_Q16, psNLSF_CB.invQuantStepSize_Q6, NLSF_mu_Q20, psNLSF_CB.order); int num3 = (signalType >> 1) * psNLSF_CB.nVectors; int inLin = ((num != 0) ? (psNLSF_CB.CB1_iCDF[num3 + num - 1] - psNLSF_CB.CB1_iCDF[num3 + num]) : (256 - psNLSF_CB.CB1_iCDF[num3 + num])); int b2 = 1024 - Inlines.silk_lin2log(inLin); array3[i] = Inlines.silk_SMLABB(array3[i], b2, Inlines.silk_RSHIFT(NLSF_mu_Q20, 2)); } int[] array5 = new int[1]; Sort.silk_insertion_sort_increasing(array3, array5, nSurvivors, 1); NLSFIndices[0] = (sbyte)array2[array5[0]]; Arrays.MemCopy(array4[array5[0]], 0, NLSFIndices, 1, psNLSF_CB.order); silk_NLSF_decode(pNLSF_Q15, NLSFIndices, psNLSF_CB); return array3[0]; } internal static void silk_NLSF2A_find_poly(int[] o, Span cLSF, int dd) { o[0] = Inlines.silk_LSHIFT(1, 16); o[1] = -cLSF[0]; for (int i = 1; i < dd; i++) { int num = cLSF[2 * i]; o[i + 1] = Inlines.silk_LSHIFT(o[i - 1], 1) - (int)Inlines.silk_RSHIFT_ROUND64(Inlines.silk_SMULL(num, o[i]), 16); for (int num2 = i; num2 > 1; num2--) { o[num2] += o[num2 - 2] - (int)Inlines.silk_RSHIFT_ROUND64(Inlines.silk_SMULL(num, o[num2 - 1]), 16); } o[1] -= num; } } internal static void silk_NLSF2A(short[] a_Q12, short[] NLSF, int d) { int[] array = new int[d]; int[] array2 = new int[d / 2 + 1]; int[] array3 = new int[d / 2 + 1]; int[] array4 = new int[d]; int num = 0; byte[] array5 = ((d == 16) ? ordering16 : ordering10); for (int i = 0; i < d; i++) { int num2 = Inlines.silk_RSHIFT(NLSF[i], 8); int b = NLSF[i] - Inlines.silk_LSHIFT(num2, 8); int num3 = Tables.silk_LSFCosTab_Q12[num2]; int a = Tables.silk_LSFCosTab_Q12[num2 + 1] - num3; array[array5[i]] = Inlines.silk_RSHIFT_ROUND(Inlines.silk_LSHIFT(num3, 8) + Inlines.silk_MUL(a, b), 4); } int num4 = Inlines.silk_RSHIFT(d, 1); silk_NLSF2A_find_poly(array2, array.AsSpan(), num4); silk_NLSF2A_find_poly(array3, array.AsSpan().Slice(1), num4); for (int i = 0; i < num4; i++) { int num5 = array2[i + 1] + array2[i]; int num6 = array3[i + 1] - array3[i]; array4[i] = -num6 - num5; array4[d - i - 1] = num6 - num5; } int j; for (j = 0; j < 10; j++) { int num7 = 0; for (int i = 0; i < d; i++) { int num8 = Inlines.silk_abs(array4[i]); if (num8 > num7) { num7 = num8; num = i; } } num7 = Inlines.silk_RSHIFT_ROUND(num7, 5); if (num7 <= 32767) { break; } num7 = Inlines.silk_min(num7, 163838); int chirp_Q = 65470 - Inlines.silk_DIV32(Inlines.silk_LSHIFT(num7 - 32767, 14), Inlines.silk_RSHIFT32(Inlines.silk_MUL(num7, num + 1), 2)); Filters.silk_bwexpander_32(array4, d, chirp_Q); } if (j == 10) { for (int i = 0; i < d; i++) { a_Q12[i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(array4[i], 5)); array4[i] = Inlines.silk_LSHIFT(a_Q12[i], 5); } } else { for (int i = 0; i < d; i++) { a_Q12[i] = (short)Inlines.silk_RSHIFT_ROUND(array4[i], 5); } } for (j = 0; j < 16; j++) { if (Filters.silk_LPC_inverse_pred_gain(a_Q12, d) >= 107374) { break; } Filters.silk_bwexpander_32(array4, d, 65536 - Inlines.silk_LSHIFT(2, j)); for (int i = 0; i < d; i++) { a_Q12[i] = (short)Inlines.silk_RSHIFT_ROUND(array4[i], 5); } } } internal static void silk_A2NLSF_trans_poly(int[] p, int dd) { for (int i = 2; i <= dd; i++) { for (int num = dd; num > i; num--) { p[num - 2] -= p[num]; } p[i - 2] -= Inlines.silk_LSHIFT(p[i], 1); } } internal static int silk_A2NLSF_eval_poly(int[] p, int x, int dd) { int num = p[dd]; int c = Inlines.silk_LSHIFT(x, 4); if (8 == dd) { num = Inlines.silk_SMLAWW(p[7], num, c); num = Inlines.silk_SMLAWW(p[6], num, c); num = Inlines.silk_SMLAWW(p[5], num, c); num = Inlines.silk_SMLAWW(p[4], num, c); num = Inlines.silk_SMLAWW(p[3], num, c); num = Inlines.silk_SMLAWW(p[2], num, c); num = Inlines.silk_SMLAWW(p[1], num, c); num = Inlines.silk_SMLAWW(p[0], num, c); } else { for (int num2 = dd - 1; num2 >= 0; num2--) { num = Inlines.silk_SMLAWW(p[num2], num, c); } } return num; } internal static void silk_A2NLSF_init(int[] a_Q16, int[] P, int[] Q, int dd) { P[dd] = Inlines.silk_LSHIFT(1, 16); Q[dd] = Inlines.silk_LSHIFT(1, 16); for (int i = 0; i < dd; i++) { P[i] = -a_Q16[dd - i - 1] - a_Q16[dd + i]; Q[i] = -a_Q16[dd - i - 1] + a_Q16[dd + i]; } for (int i = dd; i > 0; i--) { P[i - 1] -= P[i]; Q[i - 1] += Q[i]; } silk_A2NLSF_trans_poly(P, dd); silk_A2NLSF_trans_poly(Q, dd); } internal static void silk_A2NLSF(short[] NLSF, int[] a_Q16, int d) { int[] array = new int[9]; int[] array2 = new int[9]; int[][] array3 = new int[2][] { array, array2 }; int dd = Inlines.silk_RSHIFT(d, 1); silk_A2NLSF_init(a_Q16, array, array2, dd); int[] p = array; int num = Tables.silk_LSFCosTab_Q12[0]; int num2 = silk_A2NLSF_eval_poly(p, num, dd); int num3; if (num2 < 0) { NLSF[0] = 0; p = array2; num2 = silk_A2NLSF_eval_poly(p, num, dd); num3 = 1; } else { num3 = 0; } int num4 = 1; int num5 = 0; int num6 = 0; while (true) { int num7 = Tables.silk_LSFCosTab_Q12[num4]; int num8 = silk_A2NLSF_eval_poly(p, num7, dd); if ((num2 <= 0 && num8 >= num6) || (num2 >= 0 && num8 <= -num6)) { num6 = ((num8 == 0) ? 1 : 0); int num9 = -256; for (int i = 0; i < 3; i++) { int num10 = Inlines.silk_RSHIFT_ROUND(num + num7, 1); int num11 = silk_A2NLSF_eval_poly(p, num10, dd); if ((num2 <= 0 && num11 >= 0) || (num2 >= 0 && num11 <= 0)) { num7 = num10; num8 = num11; } else { num = num10; num2 = num11; num9 = Inlines.silk_ADD_RSHIFT(num9, 128, i); } } if (Inlines.silk_abs(num2) < 65536) { int num12 = num2 - num8; int a = Inlines.silk_LSHIFT(num2, 5) + Inlines.silk_RSHIFT(num12, 1); if (num12 != 0) { num9 += Inlines.silk_DIV32(a, num12); } } else { num9 += Inlines.silk_DIV32(num2, Inlines.silk_RSHIFT(num2 - num8, 5)); } NLSF[num3] = (short)Inlines.silk_min_32(Inlines.silk_LSHIFT(num4, 8) + num9, 32767); num3++; if (num3 < d) { p = array3[num3 & 1]; num = Tables.silk_LSFCosTab_Q12[num4 - 1]; num2 = Inlines.silk_LSHIFT(1 - (num3 & 2), 12); continue; } break; } num4++; num = num7; num2 = num8; num6 = 0; if (num4 <= 128) { continue; } num5++; if (num5 > 30) { NLSF[0] = (short)Inlines.silk_DIV32_16(32768, (short)(d + 1)); for (num4 = 1; num4 < d; num4++) { NLSF[num4] = (short)Inlines.silk_SMULBB(num4 + 1, NLSF[0]); } break; } Filters.silk_bwexpander_32(a_Q16, d, 65536 - Inlines.silk_SMULBB(10 + num5, num5)); silk_A2NLSF_init(a_Q16, array, array2, dd); p = array; num = Tables.silk_LSFCosTab_Q12[0]; num2 = silk_A2NLSF_eval_poly(p, num, dd); if (num2 < 0) { NLSF[0] = 0; p = array2; num2 = silk_A2NLSF_eval_poly(p, num, dd); num3 = 1; } else { num3 = 0; } num4 = 1; } } internal static void silk_process_NLSFs(SilkChannelEncoder psEncC, short[][] PredCoef_Q12, short[] pNLSF_Q15, short[] prev_NLSFq_Q15) { short[] array = new short[16]; short[] array2 = new short[16]; short[] array3 = new short[16]; int num = Inlines.silk_SMLAWB(3146, -268434, psEncC.speech_activity_Q8); if (psEncC.nb_subfr == 2) { num = Inlines.silk_ADD_RSHIFT(num, num, 1); } silk_NLSF_VQ_weights_laroia(array2, pNLSF_Q15, psEncC.predictLPCOrder); bool flag = psEncC.useInterpolatedNLSFs == 1 && psEncC.indices.NLSFInterpCoef_Q2 < 4; if (flag) { Inlines.silk_interpolate(array, prev_NLSFq_Q15, pNLSF_Q15, psEncC.indices.NLSFInterpCoef_Q2, psEncC.predictLPCOrder); silk_NLSF_VQ_weights_laroia(array3, array, psEncC.predictLPCOrder); int c = Inlines.silk_LSHIFT(Inlines.silk_SMULBB(psEncC.indices.NLSFInterpCoef_Q2, psEncC.indices.NLSFInterpCoef_Q2), 11); for (int i = 0; i < psEncC.predictLPCOrder; i++) { array2[i] = (short)Inlines.silk_SMLAWB(Inlines.silk_RSHIFT(array2[i], 1), array3[i], c); } } silk_NLSF_encode(psEncC.indices.NLSFIndices, pNLSF_Q15, psEncC.psNLSF_CB, array2, num, psEncC.NLSF_MSVQ_Survivors, psEncC.indices.signalType); silk_NLSF2A(PredCoef_Q12[1], pNLSF_Q15, psEncC.predictLPCOrder); if (flag) { Inlines.silk_interpolate(array, prev_NLSFq_Q15, pNLSF_Q15, psEncC.indices.NLSFInterpCoef_Q2, psEncC.predictLPCOrder); silk_NLSF2A(PredCoef_Q12[0], array, psEncC.predictLPCOrder); } else { Arrays.MemCopy(PredCoef_Q12[1], 0, PredCoef_Q12[0], 0, psEncC.predictLPCOrder); } } } internal static class NoiseShapeAnalysis { internal static int warped_gain(int[] coefs_Q24, int lambda_Q16, int order) { lambda_Q16 = -lambda_Q16; int b = coefs_Q24[order - 1]; for (int num = order - 2; num >= 0; num--) { b = Inlines.silk_SMLAWB(coefs_Q24[num], b, lambda_Q16); } b = Inlines.silk_SMLAWB(16777216, b, -lambda_Q16); return Inlines.silk_INVERSE32_varQ(b, 40); } internal static void limit_warped_coefs(int[] coefs_syn_Q24, int[] coefs_ana_Q24, int lambda_Q16, int limit_Q24, int order) { int num = 0; lambda_Q16 = -lambda_Q16; for (int num2 = order - 1; num2 > 0; num2--) { coefs_syn_Q24[num2 - 1] = Inlines.silk_SMLAWB(coefs_syn_Q24[num2 - 1], coefs_syn_Q24[num2], lambda_Q16); coefs_ana_Q24[num2 - 1] = Inlines.silk_SMLAWB(coefs_ana_Q24[num2 - 1], coefs_ana_Q24[num2], lambda_Q16); } lambda_Q16 = -lambda_Q16; int a = Inlines.silk_SMLAWB(65536, -lambda_Q16, lambda_Q16); int b = Inlines.silk_SMLAWB(16777216, coefs_syn_Q24[0], lambda_Q16); int num3 = Inlines.silk_DIV32_varQ(a, b, 24); b = Inlines.silk_SMLAWB(16777216, coefs_ana_Q24[0], lambda_Q16); int num4 = Inlines.silk_DIV32_varQ(a, b, 24); for (int num2 = 0; num2 < order; num2++) { coefs_syn_Q24[num2] = Inlines.silk_SMULWW(num3, coefs_syn_Q24[num2]); coefs_ana_Q24[num2] = Inlines.silk_SMULWW(num4, coefs_ana_Q24[num2]); } for (int i = 0; i < 10; i++) { int num5 = -1; for (int num2 = 0; num2 < order; num2++) { int num6 = Inlines.silk_max(Inlines.silk_abs_int32(coefs_syn_Q24[num2]), Inlines.silk_abs_int32(coefs_ana_Q24[num2])); if (num6 > num5) { num5 = num6; num = num2; } } if (num5 <= limit_Q24) { break; } for (int num2 = 1; num2 < order; num2++) { coefs_syn_Q24[num2 - 1] = Inlines.silk_SMLAWB(coefs_syn_Q24[num2 - 1], coefs_syn_Q24[num2], lambda_Q16); coefs_ana_Q24[num2 - 1] = Inlines.silk_SMLAWB(coefs_ana_Q24[num2 - 1], coefs_ana_Q24[num2], lambda_Q16); } num3 = Inlines.silk_INVERSE32_varQ(num3, 32); num4 = Inlines.silk_INVERSE32_varQ(num4, 32); for (int num2 = 0; num2 < order; num2++) { coefs_syn_Q24[num2] = Inlines.silk_SMULWW(num3, coefs_syn_Q24[num2]); coefs_ana_Q24[num2] = Inlines.silk_SMULWW(num4, coefs_ana_Q24[num2]); } int chirp_Q = 64881 - Inlines.silk_DIV32_varQ(Inlines.silk_SMULWB(num5 - limit_Q24, Inlines.silk_SMLABB(819, 102, i)), Inlines.silk_MUL(num5, num + 1), 22); BWExpander.silk_bwexpander_32(coefs_syn_Q24, order, chirp_Q); BWExpander.silk_bwexpander_32(coefs_ana_Q24, order, chirp_Q); lambda_Q16 = -lambda_Q16; for (int num2 = order - 1; num2 > 0; num2--) { coefs_syn_Q24[num2 - 1] = Inlines.silk_SMLAWB(coefs_syn_Q24[num2 - 1], coefs_syn_Q24[num2], lambda_Q16); coefs_ana_Q24[num2 - 1] = Inlines.silk_SMLAWB(coefs_ana_Q24[num2 - 1], coefs_ana_Q24[num2], lambda_Q16); } lambda_Q16 = -lambda_Q16; int a2 = Inlines.silk_SMLAWB(65536, -lambda_Q16, lambda_Q16); b = Inlines.silk_SMLAWB(16777216, coefs_syn_Q24[0], lambda_Q16); num3 = Inlines.silk_DIV32_varQ(a2, b, 24); b = Inlines.silk_SMLAWB(16777216, coefs_ana_Q24[0], lambda_Q16); num4 = Inlines.silk_DIV32_varQ(a2, b, 24); for (int num2 = 0; num2 < order; num2++) { coefs_syn_Q24[num2] = Inlines.silk_SMULWW(num3, coefs_syn_Q24[num2]); coefs_ana_Q24[num2] = Inlines.silk_SMULWW(num4, coefs_ana_Q24[num2]); } } } internal static void silk_noise_shape_analysis(SilkChannelEncoder psEnc, SilkEncoderControl psEncCtrl, short[] pitch_res, int pitch_res_ptr, short[] x, int x_ptr) { SilkShapeState sShape = psEnc.sShape; int shift = 0; int[] array = new int[17]; int[] rc_Q = new int[16]; int[] array2 = new int[16]; int[] array3 = new int[16]; int num = x_ptr - psEnc.la_shape; int num2 = psEnc.SNR_dB_Q7; psEncCtrl.input_quality_Q14 = Inlines.silk_RSHIFT(psEnc.input_quality_bands_Q15[0] + psEnc.input_quality_bands_Q15[1], 2); psEncCtrl.coding_quality_Q14 = Inlines.silk_RSHIFT(Sigmoid.silk_sigm_Q15(Inlines.silk_RSHIFT_ROUND(num2 - 2560, 4)), 1); if (psEnc.useCBR == 0) { int num3 = 256 - psEnc.speech_activity_Q8; num3 = Inlines.silk_SMULWB(Inlines.silk_LSHIFT(num3, 8), num3); num2 = Inlines.silk_SMLAWB(num2, Inlines.silk_SMULBB(-8, num3), Inlines.silk_SMULWB(16384 + psEncCtrl.input_quality_Q14, psEncCtrl.coding_quality_Q14)); } num2 = ((psEnc.indices.signalType != 2) ? Inlines.silk_SMLAWB(num2, Inlines.silk_SMLAWB(3072, -104858, psEnc.SNR_dB_Q7), 16384 - psEncCtrl.input_quality_Q14) : Inlines.silk_SMLAWB(num2, 512, psEnc.LTPCorr_Q15)); if (psEnc.indices.signalType == 2) { psEnc.indices.quantOffsetType = 0; psEncCtrl.sparseness_Q8 = 0; } else { int num4 = Inlines.silk_LSHIFT(psEnc.fs_kHz, 1); int num5 = 0; int num6 = 0; int num7 = pitch_res_ptr; for (int i = 0; i < Inlines.silk_SMULBB(5, psEnc.nb_subfr) / 2; i++) { SumSqrShift.silk_sum_sqr_shift(out var energy, out shift, pitch_res, num7, num4); energy += Inlines.silk_RSHIFT(num4, shift); int num8 = Inlines.silk_lin2log(energy); if (i > 0) { num5 += Inlines.silk_abs(num8 - num6); } num6 = num8; num7 += num4; } psEncCtrl.sparseness_Q8 = Inlines.silk_RSHIFT(Sigmoid.silk_sigm_Q15(Inlines.silk_SMULWB(num5 - 640, 6554)), 7); if (psEncCtrl.sparseness_Q8 > 192) { psEnc.indices.quantOffsetType = 0; } else { psEnc.indices.quantOffsetType = 1; } num2 = Inlines.silk_SMLAWB(num2, 65536, psEncCtrl.sparseness_Q8 - 128); } int num9 = Inlines.silk_SMULWB(psEncCtrl.predGain_Q16, 66); int a; int a2 = (a = Inlines.silk_DIV32_varQ(62259, Inlines.silk_SMLAWW(65536, num9, num9), 16)); int b = Inlines.silk_SMULWB(65536 - Inlines.silk_SMULBB(3, psEncCtrl.coding_quality_Q14), 655); a2 = Inlines.silk_SUB32(a2, b); a = Inlines.silk_ADD32(a, b); a2 = Inlines.silk_DIV32_16(Inlines.silk_LSHIFT(a2, 14), Inlines.silk_RSHIFT(a, 2)); int num10 = ((psEnc.warping_Q16 > 0) ? Inlines.silk_SMLAWB(psEnc.warping_Q16, psEncCtrl.coding_quality_Q14, 2621) : 0); short[] array4 = new short[psEnc.shapeWinLength]; int b2; for (int i = 0; i < psEnc.nb_subfr; i++) { int num11 = psEnc.fs_kHz * 3; int num12 = Inlines.silk_RSHIFT(psEnc.shapeWinLength - num11, 1); ApplySineWindow.silk_apply_sine_window(array4, 0, x, num, 1, num12); int num13 = num12; Arrays.MemCopy(x, num + num13, array4, num13, num11); num13 += num11; ApplySineWindow.silk_apply_sine_window(array4, num13, x, num + num13, 2, num12); num += psEnc.subfr_length; if (psEnc.warping_Q16 > 0) { Autocorrelation.silk_warped_autocorrelation(array, out shift, array4, num10, psEnc.shapeWinLength, psEnc.shapingLPCOrder); } else { Autocorrelation.silk_autocorr(array, out shift, array4, psEnc.shapeWinLength, psEnc.shapingLPCOrder + 1); } array[0] = Inlines.silk_ADD32(array[0], Inlines.silk_max_32(Inlines.silk_SMULWB(Inlines.silk_RSHIFT(array[0], 4), 52), 1)); int energy = Schur.silk_schur64(rc_Q, array, psEnc.shapingLPCOrder); K2A.silk_k2a_Q16(array3, rc_Q, psEnc.shapingLPCOrder); int num14 = -shift; if (((uint)num14 & (true ? 1u : 0u)) != 0) { num14--; energy >>= 1; } int a3 = Inlines.silk_SQRT_APPROX(energy); num14 >>= 1; psEncCtrl.Gains_Q16[i] = Inlines.silk_LSHIFT_SAT32(a3, 16 - num14); if (psEnc.warping_Q16 > 0) { b2 = warped_gain(array3, num10, psEnc.shapingLPCOrder); if (Inlines.silk_SMULWW(Inlines.silk_RSHIFT_ROUND(psEncCtrl.Gains_Q16[i], 1), b2) >= 1073741823) { psEncCtrl.Gains_Q16[i] = int.MaxValue; } else { psEncCtrl.Gains_Q16[i] = Inlines.silk_SMULWW(psEncCtrl.Gains_Q16[i], b2); } } BWExpander.silk_bwexpander_32(array3, psEnc.shapingLPCOrder, a); Arrays.MemCopy(array3, 0, array2, 0, psEnc.shapingLPCOrder); BWExpander.silk_bwexpander_32(array2, psEnc.shapingLPCOrder, a2); int a4 = LPCInversePredGain.silk_LPC_inverse_pred_gain_Q24(array3, psEnc.shapingLPCOrder); energy = LPCInversePredGain.silk_LPC_inverse_pred_gain_Q24(array2, psEnc.shapingLPCOrder); a4 = Inlines.silk_LSHIFT32(Inlines.silk_SMULWB(a4, 22938), 1); psEncCtrl.GainsPre_Q14[i] = 4915 + Inlines.silk_DIV32_varQ(a4, energy, 14); limit_warped_coefs(array3, array2, num10, 67092088, psEnc.shapingLPCOrder); for (int j = 0; j < psEnc.shapingLPCOrder; j++) { psEncCtrl.AR1_Q13[i * 16 + j] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(array2[j], 11)); psEncCtrl.AR2_Q13[i * 16 + j] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(array3[j], 11)); } } b2 = Inlines.silk_log2lin(-Inlines.silk_SMLAWB(-2048, num2, 10486)); int b3 = Inlines.silk_log2lin(Inlines.silk_SMLAWB(2048, 256, 10486)); for (int i = 0; i < psEnc.nb_subfr; i++) { psEncCtrl.Gains_Q16[i] = Inlines.silk_SMULWW(psEncCtrl.Gains_Q16[i], b2); psEncCtrl.Gains_Q16[i] = Inlines.silk_ADD_POS_SAT32(psEncCtrl.Gains_Q16[i], b3); } b2 = 65536 + Inlines.silk_RSHIFT_ROUND(Inlines.silk_MLA(3355443, psEncCtrl.coding_quality_Q14, 410), 10); for (int i = 0; i < psEnc.nb_subfr; i++) { psEncCtrl.GainsPre_Q14[i] = Inlines.silk_SMULWB(b2, psEncCtrl.GainsPre_Q14[i]); } num9 = Inlines.silk_MUL(64, Inlines.silk_SMLAWB(4096, 4096, psEnc.input_quality_bands_Q15[0] - 32768)); num9 = Inlines.silk_RSHIFT(Inlines.silk_MUL(num9, psEnc.speech_activity_Q8), 8); int num17; if (psEnc.indices.signalType == 2) { int num15 = Inlines.silk_DIV32_16(3277, psEnc.fs_kHz); for (int i = 0; i < psEnc.nb_subfr; i++) { int num16 = num15 + Inlines.silk_DIV32_16(49152, psEncCtrl.pitchL[i]); psEncCtrl.LF_shp_Q14[i] = Inlines.silk_LSHIFT(16384 - num16 - Inlines.silk_SMULWB(num9, num16), 16); psEncCtrl.LF_shp_Q14[i] |= (num16 - 16384) & 0xFFFF; } num17 = -16384 - Inlines.silk_SMULWB(49152, Inlines.silk_SMULWB(5872026, psEnc.speech_activity_Q8)); } else { int num16 = Inlines.silk_DIV32_16(21299, psEnc.fs_kHz); psEncCtrl.LF_shp_Q14[0] = Inlines.silk_LSHIFT(16384 - num16 - Inlines.silk_SMULWB(num9, Inlines.silk_SMULWB(39322, num16)), 16); psEncCtrl.LF_shp_Q14[0] |= (num16 - 16384) & 0xFFFF; for (int i = 1; i < psEnc.nb_subfr; i++) { psEncCtrl.LF_shp_Q14[i] = psEncCtrl.LF_shp_Q14[0]; } num17 = -16384; } int a5 = Inlines.silk_SMULWB(Inlines.silk_SMULWB(131072 - Inlines.silk_LSHIFT(psEncCtrl.coding_quality_Q14, 3), psEnc.LTPCorr_Q15), 6554); a5 = Inlines.silk_SMLAWB(a5, 65536 - Inlines.silk_LSHIFT(psEncCtrl.input_quality_Q14, 2), 6554); int a6; if (psEnc.indices.signalType == 2) { a6 = Inlines.silk_SMLAWB(19661, 65536 - Inlines.silk_SMULWB(262144 - Inlines.silk_LSHIFT(psEncCtrl.coding_quality_Q14, 4), psEncCtrl.input_quality_Q14), 13107); a6 = Inlines.silk_SMULWB(Inlines.silk_LSHIFT(a6, 1), Inlines.silk_SQRT_APPROX(Inlines.silk_LSHIFT(psEnc.LTPCorr_Q15, 15))); } else { a6 = 0; } for (int i = 0; i < 4; i++) { sShape.HarmBoost_smth_Q16 = Inlines.silk_SMLAWB(sShape.HarmBoost_smth_Q16, a5 - sShape.HarmBoost_smth_Q16, 26214); sShape.HarmShapeGain_smth_Q16 = Inlines.silk_SMLAWB(sShape.HarmShapeGain_smth_Q16, a6 - sShape.HarmShapeGain_smth_Q16, 26214); sShape.Tilt_smth_Q16 = Inlines.silk_SMLAWB(sShape.Tilt_smth_Q16, num17 - sShape.Tilt_smth_Q16, 26214); psEncCtrl.HarmBoost_Q14[i] = Inlines.silk_RSHIFT_ROUND(sShape.HarmBoost_smth_Q16, 2); psEncCtrl.HarmShapeGain_Q14[i] = Inlines.silk_RSHIFT_ROUND(sShape.HarmShapeGain_smth_Q16, 2); psEncCtrl.Tilt_Q14[i] = Inlines.silk_RSHIFT_ROUND(sShape.Tilt_smth_Q16, 2); } } } internal static class PitchAnalysisCore { private class silk_pe_stage3_vals { internal readonly int[] Values = new int[5]; } private const int SCRATCH_SIZE = 22; private const int SF_LENGTH_4KHZ = 20; private const int SF_LENGTH_8KHZ = 40; private const int MIN_LAG_4KHZ = 8; private const int MIN_LAG_8KHZ = 16; private const int MAX_LAG_4KHZ = 72; private const int MAX_LAG_8KHZ = 143; private const int CSTRIDE_4KHZ = 65; private const int CSTRIDE_8KHZ = 132; private const int D_COMP_MIN = 13; private const int D_COMP_MAX = 147; private const int D_COMP_STRIDE = 134; internal static int silk_pitch_analysis_core(short[] frame, int[] pitch_out, BoxedValueShort lagIndex, BoxedValueSbyte contourIndex, BoxedValueInt LTPCorr_Q15, int prevLag, int search_thres1_Q16, int search_thres2_Q13, int Fs_kHz, int complexity, int nb_subfr) { int[] array = new int[6]; int[] array2 = new int[24]; int[] array3 = new int[11]; int num = (20 + nb_subfr * 5) * Fs_kHz; int num2 = (20 + nb_subfr * 5) * 4; int num3 = (20 + nb_subfr * 5) * 8; int num4 = 5 * Fs_kHz; int num5 = 2 * Fs_kHz; int num6 = 18 * Fs_kHz - 1; short[] array4 = new short[num3]; switch (Fs_kHz) { case 16: Arrays.MemSetInt(array, 0, 2); Resampler.silk_resampler_down2(array, array4, frame, num); break; case 12: Arrays.MemSetInt(array, 0, 6); Resampler.silk_resampler_down2_3(array, array4, frame, num); break; default: Arrays.MemCopy(frame, 0, array4, 0, num3); break; } Arrays.MemSetInt(array, 0, 2); short[] array5 = new short[num2]; Resampler.silk_resampler_down2(array, array5, array4, num3); for (int num7 = num2 - 1; num7 > 0; num7--) { array5[num7] = Inlines.silk_ADD_SAT16(array5[num7], array5[num7 - 1]); } SumSqrShift.silk_sum_sqr_shift(out var energy, out var shift, array5, num2); if (shift > 0) { shift = Inlines.silk_RSHIFT(shift, 1); for (int num7 = 0; num7 < num2; num7++) { array5[num7] = Inlines.silk_RSHIFT16(array5[num7], shift); } } short[] array6 = new short[nb_subfr * 132]; int[] array7 = new int[65]; Arrays.MemSetShort(array6, 0, (nb_subfr >> 1) * 65); short[] array8 = array5; int num8 = Inlines.silk_LSHIFT(20, 2); for (int i = 0; i < nb_subfr >> 1; i++) { short[] array9 = array8; int num9 = num8 - 8; CeltPitchXCorr.pitch_xcorr(array8, num8, array8, num8 - 72, array7, 40, 65); int a = array7[64]; int a2 = Inlines.silk_inner_prod_self(array8, num8, 40); a2 = Inlines.silk_ADD32(a2, Inlines.silk_inner_prod_self(array9, num9, 40)); a2 = Inlines.silk_ADD32(a2, Inlines.silk_SMULBB(40, 4000)); Inlines.MatrixSet(array6, i, 0, 65, (short)Inlines.silk_DIV32_varQ(a, a2, 14)); for (int j = 9; j <= 72; j++) { num9--; a = array7[72 - j]; a2 = Inlines.silk_ADD32(a2, Inlines.silk_SMULBB(array9[num9], array9[num9]) - Inlines.silk_SMULBB(array9[num9 + 40], array9[num9 + 40])); Inlines.MatrixSet(array6, i, j - 8, 65, (short)Inlines.silk_DIV32_varQ(a, a2, 14)); } num8 += 40; } if (nb_subfr == 4) { for (int num7 = 72; num7 >= 8; num7--) { int num10 = Inlines.MatrixGet(array6, 0, num7 - 8, 65) + Inlines.MatrixGet(array6, 1, num7 - 8, 65); num10 = Inlines.silk_SMLAWB(num10, num10, Inlines.silk_LSHIFT(-num7, 4)); array6[num7 - 8] = (short)num10; } } else { for (int num7 = 72; num7 >= 8; num7--) { int num10 = Inlines.silk_LSHIFT(array6[num7 - 8], 1); num10 = Inlines.silk_SMLAWB(num10, num10, Inlines.silk_LSHIFT(-num7, 4)); array6[num7 - 8] = (short)num10; } } int num11 = Inlines.silk_ADD_LSHIFT32(4, complexity, 1); Sort.silk_insertion_sort_decreasing_int16(array6, array2, 65, num11); int num12 = array6[0]; if (num12 < 3277) { Arrays.MemSetInt(pitch_out, 0, nb_subfr); LTPCorr_Q15.Val = 0; lagIndex.Val = 0; contourIndex.Val = 0; return 1; } int num13 = Inlines.silk_SMULWB(search_thres1_Q16, num12); for (int num7 = 0; num7 < num11; num7++) { if (array6[num7] > num13) { array2[num7] = Inlines.silk_LSHIFT(array2[num7] + 8, 1); continue; } num11 = num7; break; } short[] array10 = new short[134]; for (int num7 = 13; num7 < 147; num7++) { array10[num7 - 13] = 0; } for (int num7 = 0; num7 < num11; num7++) { array10[array2[num7] - 13] = 1; } for (int num7 = 146; num7 >= 16; num7--) { array10[num7 - 13] += (short)(array10[num7 - 1 - 13] + array10[num7 - 2 - 13]); } num11 = 0; for (int num7 = 16; num7 < 144; num7++) { if (array10[num7 + 1 - 13] > 0) { array2[num11] = num7; num11++; } } for (int num7 = 146; num7 >= 16; num7--) { array10[num7 - 13] += (short)(array10[num7 - 1 - 13] + array10[num7 - 2 - 13] + array10[num7 - 3 - 13]); } int num14 = 0; for (int num7 = 16; num7 < 147; num7++) { if (array10[num7 - 13] > 0) { array10[num14] = (short)(num7 - 2); num14++; } } SumSqrShift.silk_sum_sqr_shift(out energy, out shift, array4, num3); if (shift > 0) { shift = Inlines.silk_RSHIFT(shift, 1); for (int num7 = 0; num7 < num3; num7++) { array4[num7] = Inlines.silk_RSHIFT16(array4[num7], shift); } } Arrays.MemSetShort(array6, 0, nb_subfr * 132); array8 = array4; num8 = 160; for (int i = 0; i < nb_subfr; i++) { int a3 = Inlines.silk_ADD32(Inlines.silk_inner_prod(array8, num8, array8, num8, 40), 1); for (int k = 0; k < num14; k++) { int j = array10[k]; short[] array9 = array8; int num9 = num8 - j; int a = Inlines.silk_inner_prod(array8, num8, array9, num9, 40); if (a > 0) { int b = Inlines.silk_inner_prod_self(array9, num9, 40); Inlines.MatrixSet(array6, i, j - 14, 132, (short)Inlines.silk_DIV32_varQ(a, Inlines.silk_ADD32(a3, b), 14)); } else { Inlines.MatrixSet(array6, i, j - 14, 132, (short)0); } } num8 += 40; } int a4 = int.MinValue; int num15 = int.MinValue; int num16 = 0; int num17 = -1; int num18; if (prevLag > 0) { switch (Fs_kHz) { case 12: prevLag = Inlines.silk_DIV32_16(Inlines.silk_LSHIFT(prevLag, 1), 3); break; case 16: prevLag = Inlines.silk_RSHIFT(prevLag, 1); break; } num18 = Inlines.silk_lin2log(prevLag); } else { num18 = 0; } int num19; sbyte[][] array11; if (nb_subfr == 4) { array11 = Tables.silk_CB_lags_stage2; num19 = ((Fs_kHz != 8 || complexity <= 0) ? 3 : 11); } else { array11 = Tables.silk_CB_lags_stage2_10_ms; num19 = 3; } for (int i = 0; i < num11; i++) { int j = array2[i]; for (int k = 0; k < num19; k++) { array3[k] = 0; for (int num7 = 0; num7 < nb_subfr; num7++) { int num20 = j + array11[num7][k]; array3[k] += Inlines.MatrixGet(array6, num7, num20 - 14, 132); } } int num21 = int.MinValue; int num22 = 0; for (int num7 = 0; num7 < num19; num7++) { if (array3[num7] > num21) { num21 = array3[num7]; num22 = num7; } } int num23 = Inlines.silk_lin2log(j); int num24 = num21 - Inlines.silk_RSHIFT(Inlines.silk_SMULBB(nb_subfr * 1638, num23), 7); if (prevLag > 0) { int num25 = num23 - num18; num25 = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(num25, num25), 7); int a5 = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(nb_subfr * 1638, LTPCorr_Q15.Val), 15); a5 = Inlines.silk_DIV32(Inlines.silk_MUL(a5, num25), num25 + 64); num24 -= a5; } if (num24 > num15 && num21 > Inlines.silk_SMULBB(nb_subfr, search_thres2_Q13) && Tables.silk_CB_lags_stage2[0][num22] <= 16) { num15 = num24; a4 = num21; num17 = j; num16 = num22; } } if (num17 == -1) { Arrays.MemSetInt(pitch_out, 0, nb_subfr); LTPCorr_Q15.Val = 0; lagIndex.Val = 0; contourIndex.Val = 0; return 1; } LTPCorr_Q15.Val = Inlines.silk_LSHIFT(Inlines.silk_DIV32_16(a4, nb_subfr), 2); if (Fs_kHz > 8) { SumSqrShift.silk_sum_sqr_shift(out energy, out shift, frame, num); short[] array13; if (shift > 0) { short[] array12 = new short[num]; shift = Inlines.silk_RSHIFT(shift, 1); for (int num7 = 0; num7 < num; num7++) { array12[num7] = Inlines.silk_RSHIFT16(frame[num7], shift); } array13 = array12; } else { array13 = frame; } int num26 = num16; num17 = Inlines.silk_LIMIT_int(Fs_kHz switch { 12 => Inlines.silk_RSHIFT(Inlines.silk_SMULBB(num17, 3), 1), 16 => Inlines.silk_LSHIFT(num17, 1), _ => Inlines.silk_SMULBB(num17, 3), }, num5, num6); int num27 = Inlines.silk_max_int(num17 - 2, num5); int num28 = Inlines.silk_min_int(num17 + 2, num6); int num29 = num17; num16 = 0; a4 = int.MinValue; for (int i = 0; i < nb_subfr; i++) { pitch_out[i] = num17 + 2 * Tables.silk_CB_lags_stage2[i][num26]; } if (nb_subfr == 4) { num19 = Tables.silk_nb_cbk_searchs_stage3[complexity]; array11 = Tables.silk_CB_lags_stage3; } else { num19 = 12; array11 = Tables.silk_CB_lags_stage3_10_ms; } silk_pe_stage3_vals[] array14 = new silk_pe_stage3_vals[nb_subfr * num19]; silk_pe_stage3_vals[] array15 = new silk_pe_stage3_vals[nb_subfr * num19]; for (int l = 0; l < nb_subfr * num19; l++) { array14[l] = new silk_pe_stage3_vals(); array15[l] = new silk_pe_stage3_vals(); } silk_P_Ana_calc_corr_st3(array15, array13, num27, num4, nb_subfr, complexity); silk_P_Ana_calc_energy_st3(array14, array13, num27, num4, nb_subfr, complexity); int num30 = 0; int a6 = Inlines.silk_DIV32_16(1638, num17); array8 = array13; num8 = 20 * Fs_kHz; int a3 = Inlines.silk_ADD32(Inlines.silk_inner_prod_self(array8, num8, nb_subfr * num4), 1); for (int j = num27; j <= num28; j++) { for (int k = 0; k < num19; k++) { int a = 0; energy = a3; for (int i = 0; i < nb_subfr; i++) { a = Inlines.silk_ADD32(a, Inlines.MatrixGet(array15, i, k, num19).Values[num30]); energy = Inlines.silk_ADD32(energy, Inlines.MatrixGet(array14, i, k, num19).Values[num30]); } int num21; if (a > 0) { num21 = Inlines.silk_DIV32_varQ(a, energy, 14); int b2 = 32767 - Inlines.silk_MUL(a6, k); num21 = Inlines.silk_SMULWB(num21, b2); } else { num21 = 0; } if (num21 > a4 && j + Tables.silk_CB_lags_stage3[0][k] <= num6) { a4 = num21; num29 = j; num16 = k; } } num30++; } for (int i = 0; i < nb_subfr; i++) { pitch_out[i] = num29 + array11[i][num16]; pitch_out[i] = Inlines.silk_LIMIT(pitch_out[i], num5, 18 * Fs_kHz); } lagIndex.Val = (short)(num29 - num5); contourIndex.Val = (sbyte)num16; } else { for (int i = 0; i < nb_subfr; i++) { pitch_out[i] = num17 + array11[i][num16]; pitch_out[i] = Inlines.silk_LIMIT(pitch_out[i], 16, 144); } lagIndex.Val = (short)(num17 - 16); contourIndex.Val = (sbyte)num16; } return 0; } private static void silk_P_Ana_calc_corr_st3(silk_pe_stage3_vals[] cross_corr_st3, short[] frame, int start_lag, int sf_length, int nb_subfr, int complexity) { sbyte[][] array; sbyte[][] array2; int num; if (nb_subfr == 4) { array = Tables.silk_Lag_range_stage3[complexity]; array2 = Tables.silk_CB_lags_stage3; num = Tables.silk_nb_cbk_searchs_stage3[complexity]; } else { array = Tables.silk_Lag_range_stage3_10_ms; array2 = Tables.silk_CB_lags_stage3_10_ms; num = 12; } int[] array3 = new int[22]; int[] array4 = new int[22]; int num2 = Inlines.silk_LSHIFT(sf_length, 2); for (int i = 0; i < nb_subfr; i++) { int num3 = 0; int num4 = array[i][0]; int num5 = array[i][1]; CeltPitchXCorr.pitch_xcorr(frame, num2, frame, num2 - start_lag - num5, array4, sf_length, num5 - num4 + 1); for (int j = num4; j <= num5; j++) { array3[num3] = array4[num5 - j]; num3++; } int num6 = array[i][0]; for (int k = 0; k < num; k++) { int num7 = array2[i][k] - num6; for (int j = 0; j < 5; j++) { Inlines.MatrixGet(cross_corr_st3, i, k, num).Values[j] = array3[num7 + j]; } } num2 += sf_length; } } private static void silk_P_Ana_calc_energy_st3(silk_pe_stage3_vals[] energies_st3, short[] frame, int start_lag, int sf_length, int nb_subfr, int complexity) { sbyte[][] array; sbyte[][] array2; int num; if (nb_subfr == 4) { array = Tables.silk_Lag_range_stage3[complexity]; array2 = Tables.silk_CB_lags_stage3; num = Tables.silk_nb_cbk_searchs_stage3[complexity]; } else { array = Tables.silk_Lag_range_stage3_10_ms; array2 = Tables.silk_CB_lags_stage3_10_ms; num = 12; } int[] array3 = new int[22]; int num2 = Inlines.silk_LSHIFT(sf_length, 2); for (int i = 0; i < nb_subfr; i++) { int num3 = 0; int num4 = num2 - (start_lag + array[i][0]); int num5 = (array3[num3] = Inlines.silk_inner_prod_self(frame, num4, sf_length)); num3++; int num6 = array[i][1] - array[i][0] + 1; for (int j = 1; j < num6; j++) { num5 -= Inlines.silk_SMULBB(frame[num4 + sf_length - j], frame[num4 + sf_length - j]); num5 = (array3[num3] = Inlines.silk_ADD_SAT32(num5, Inlines.silk_SMULBB(frame[num4 - j], frame[num4 - j]))); num3++; } int num7 = array[i][0]; for (int j = 0; j < num; j++) { int num8 = array2[i][j] - num7; for (int k = 0; k < 5; k++) { Inlines.MatrixGet(energies_st3, i, j, num).Values[k] = array3[num8 + k]; } } num2 += sf_length; } } } internal static class PLC { private const int NB_ATT = 2; private static readonly short[] HARM_ATT_Q15 = new short[2] { 32440, 31130 }; private static readonly short[] PLC_RAND_ATTENUATE_V_Q15 = new short[2] { 31130, 26214 }; private static readonly short[] PLC_RAND_ATTENUATE_UV_Q15 = new short[2] { 32440, 29491 }; internal static void silk_PLC_Reset(SilkChannelDecoder psDec) { psDec.sPLC.pitchL_Q8 = Inlines.silk_LSHIFT(psDec.frame_length, 7); psDec.sPLC.prevGain_Q16[0] = 65536; psDec.sPLC.prevGain_Q16[1] = 65536; psDec.sPLC.subfr_length = 20; psDec.sPLC.nb_subfr = 2; } internal static void silk_PLC(SilkChannelDecoder psDec, SilkDecoderControl psDecCtrl, Span frame, int frame_ptr, int lost) { if (psDec.fs_kHz != psDec.sPLC.fs_kHz) { silk_PLC_Reset(psDec); psDec.sPLC.fs_kHz = psDec.fs_kHz; } if (lost != 0) { silk_PLC_conceal(psDec, psDecCtrl, frame, frame_ptr); psDec.lossCnt++; } else { silk_PLC_update(psDec, psDecCtrl); } } internal static void silk_PLC_update(SilkChannelDecoder psDec, SilkDecoderControl psDecCtrl) { PLCStruct sPLC = psDec.sPLC; psDec.prevSignalType = psDec.indices.signalType; int num = 0; if (psDec.indices.signalType == 2) { for (int i = 0; i * psDec.subfr_length < psDecCtrl.pitchL[psDec.nb_subfr - 1] && i != psDec.nb_subfr; i++) { int num2 = 0; for (int j = 0; j < 5; j++) { num2 += psDecCtrl.LTPCoef_Q14[(psDec.nb_subfr - 1 - i) * 5 + j]; } if (num2 > num) { num = num2; Arrays.MemCopy(psDecCtrl.LTPCoef_Q14, Inlines.silk_SMULBB(psDec.nb_subfr - 1 - i, 5), sPLC.LTPCoef_Q14, 0, 5); sPLC.pitchL_Q8 = Inlines.silk_LSHIFT(psDecCtrl.pitchL[psDec.nb_subfr - 1 - i], 8); } } Arrays.MemSetShort(sPLC.LTPCoef_Q14, 0, 5); sPLC.LTPCoef_Q14[2] = (short)num; if (num < 11469) { int b = Inlines.silk_DIV32(Inlines.silk_LSHIFT(11469, 10), Inlines.silk_max(num, 1)); for (int j = 0; j < 5; j++) { sPLC.LTPCoef_Q14[j] = (short)Inlines.silk_RSHIFT(Inlines.silk_SMULBB(sPLC.LTPCoef_Q14[j], b), 10); } } else if (num > 15565) { int b2 = Inlines.silk_DIV32(Inlines.silk_LSHIFT(15565, 14), Inlines.silk_max(num, 1)); for (int j = 0; j < 5; j++) { sPLC.LTPCoef_Q14[j] = (short)Inlines.silk_RSHIFT(Inlines.silk_SMULBB(sPLC.LTPCoef_Q14[j], b2), 14); } } } else { sPLC.pitchL_Q8 = Inlines.silk_LSHIFT(Inlines.silk_SMULBB(psDec.fs_kHz, 18), 8); Arrays.MemSetShort(sPLC.LTPCoef_Q14, 0, 5); } Arrays.MemCopy(psDecCtrl.PredCoef_Q12[1], 0, sPLC.prevLPC_Q12, 0, psDec.LPC_order); sPLC.prevLTP_scale_Q14 = (short)psDecCtrl.LTP_scale_Q14; Arrays.MemCopy(psDecCtrl.Gains_Q16, psDec.nb_subfr - 2, sPLC.prevGain_Q16, 0, 2); sPLC.subfr_length = psDec.subfr_length; sPLC.nb_subfr = psDec.nb_subfr; } internal static void silk_PLC_energy(out int energy1, out int shift1, out int energy2, out int shift2, int[] exc_Q14, int[] prevGain_Q10, int subfr_length, int nb_subfr) { int num = 0; short[] array = new short[2 * subfr_length]; for (int i = 0; i < 2; i++) { for (int j = 0; j < subfr_length; j++) { array[num + j] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT(Inlines.silk_SMULWW(exc_Q14[j + (i + nb_subfr - 2) * subfr_length], prevGain_Q10[i]), 8)); } num += subfr_length; } SumSqrShift.silk_sum_sqr_shift(out energy1, out shift1, array, subfr_length); SumSqrShift.silk_sum_sqr_shift(out energy2, out shift2, array, subfr_length, subfr_length); } internal static void silk_PLC_conceal(SilkChannelDecoder psDec, SilkDecoderControl psDecCtrl, Span frame, int frame_ptr) { short[] array = new short[psDec.ltp_mem_length]; int[] array2 = new int[psDec.ltp_mem_length + psDec.frame_length]; PLCStruct sPLC = psDec.sPLC; int[] array3 = new int[2] { Inlines.silk_RSHIFT(sPLC.prevGain_Q16[0], 6), Inlines.silk_RSHIFT(sPLC.prevGain_Q16[1], 6) }; if (psDec.first_frame_after_reset != 0) { Arrays.MemSetShort(sPLC.prevLPC_Q12, 0, 16); } silk_PLC_energy(out var energy, out var shift, out var energy2, out var shift2, psDec.exc_Q14, array3, psDec.subfr_length, psDec.nb_subfr); int num = ((Inlines.silk_RSHIFT(energy, shift2) >= Inlines.silk_RSHIFT(energy2, shift)) ? Inlines.silk_max_int(0, sPLC.nb_subfr * sPLC.subfr_length - 128) : Inlines.silk_max_int(0, (sPLC.nb_subfr - 1) * sPLC.subfr_length - 128)); short[] lTPCoef_Q = sPLC.LTPCoef_Q14; short num2 = sPLC.randScale_Q14; int a = HARM_ATT_Q15[Inlines.silk_min_int(1, psDec.lossCnt)]; int b = ((psDec.prevSignalType != 2) ? PLC_RAND_ATTENUATE_UV_Q15[Inlines.silk_min_int(1, psDec.lossCnt)] : PLC_RAND_ATTENUATE_V_Q15[Inlines.silk_min_int(1, psDec.lossCnt)]); BWExpander.silk_bwexpander(sPLC.prevLPC_Q12, psDec.LPC_order, 64881); if (psDec.lossCnt == 0) { num2 = 16384; if (psDec.prevSignalType == 2) { for (int i = 0; i < 5; i++) { num2 -= lTPCoef_Q[i]; } num2 = Inlines.silk_max_16(3277, num2); num2 = (short)Inlines.silk_RSHIFT(Inlines.silk_SMULBB(num2, sPLC.prevLTP_scale_Q14), 14); } else { int b2 = LPCInversePredGain.silk_LPC_inverse_pred_gain(sPLC.prevLPC_Q12, psDec.LPC_order); int b3 = Inlines.silk_min_32(Inlines.silk_RSHIFT(1073741824, 3), b2); b3 = Inlines.silk_max_32(Inlines.silk_RSHIFT(1073741824, 8), b3); b3 = Inlines.silk_LSHIFT(b3, 3); b = Inlines.silk_RSHIFT(Inlines.silk_SMULWB(b3, b), 14); } } int num3 = sPLC.rand_seed; int num4 = Inlines.silk_RSHIFT_ROUND(sPLC.pitchL_Q8, 8); int num5 = psDec.ltp_mem_length; int num6 = psDec.ltp_mem_length - num4 - psDec.LPC_order - 2; Filters.silk_LPC_analysis_filter(array, num6, psDec.outBuf, num6, sPLC.prevLPC_Q12, 0, psDec.ltp_mem_length - num6, psDec.LPC_order); int a2 = Inlines.silk_INVERSE32_varQ(sPLC.prevGain_Q16[1], 46); a2 = Inlines.silk_min(a2, 1073741823); for (int i = num6 + psDec.LPC_order; i < psDec.ltp_mem_length; i++) { array2[i] = Inlines.silk_SMULWB(a2, array[i]); } for (int j = 0; j < psDec.nb_subfr; j++) { int num7 = num5 - num4 + 2; for (int i = 0; i < psDec.subfr_length; i++) { int a3 = 2; a3 = Inlines.silk_SMLAWB(a3, array2[num7], lTPCoef_Q[0]); a3 = Inlines.silk_SMLAWB(a3, array2[num7 - 1], lTPCoef_Q[1]); a3 = Inlines.silk_SMLAWB(a3, array2[num7 - 2], lTPCoef_Q[2]); a3 = Inlines.silk_SMLAWB(a3, array2[num7 - 3], lTPCoef_Q[3]); a3 = Inlines.silk_SMLAWB(a3, array2[num7 - 4], lTPCoef_Q[4]); num7++; num3 = Inlines.silk_RAND(num3); num6 = Inlines.silk_RSHIFT(num3, 25) & 0x7F; array2[num5] = Inlines.silk_LSHIFT32(Inlines.silk_SMLAWB(a3, psDec.exc_Q14[num + num6], num2), 2); num5++; } for (int k = 0; k < 5; k++) { lTPCoef_Q[k] = (short)Inlines.silk_RSHIFT(Inlines.silk_SMULBB(a, lTPCoef_Q[k]), 15); } num2 = (short)Inlines.silk_RSHIFT(Inlines.silk_SMULBB(num2, b), 15); sPLC.pitchL_Q8 = Inlines.silk_SMLAWB(sPLC.pitchL_Q8, sPLC.pitchL_Q8, 655); sPLC.pitchL_Q8 = Inlines.silk_min_32(sPLC.pitchL_Q8, Inlines.silk_LSHIFT(Inlines.silk_SMULBB(18, psDec.fs_kHz), 8)); num4 = Inlines.silk_RSHIFT_ROUND(sPLC.pitchL_Q8, 8); } int num8 = psDec.ltp_mem_length - 16; Arrays.MemCopy(psDec.sLPC_Q14_buf, 0, array2, num8, 16); for (int i = 0; i < psDec.frame_length; i++) { int num9 = num8 + 16 + i; int a4 = Inlines.silk_RSHIFT(psDec.LPC_order, 1); a4 = Inlines.silk_SMLAWB(a4, array2[num9 - 1], sPLC.prevLPC_Q12[0]); a4 = Inlines.silk_SMLAWB(a4, array2[num9 - 2], sPLC.prevLPC_Q12[1]); a4 = Inlines.silk_SMLAWB(a4, array2[num9 - 3], sPLC.prevLPC_Q12[2]); a4 = Inlines.silk_SMLAWB(a4, array2[num9 - 4], sPLC.prevLPC_Q12[3]); a4 = Inlines.silk_SMLAWB(a4, array2[num9 - 5], sPLC.prevLPC_Q12[4]); a4 = Inlines.silk_SMLAWB(a4, array2[num9 - 6], sPLC.prevLPC_Q12[5]); a4 = Inlines.silk_SMLAWB(a4, array2[num9 - 7], sPLC.prevLPC_Q12[6]); a4 = Inlines.silk_SMLAWB(a4, array2[num9 - 8], sPLC.prevLPC_Q12[7]); a4 = Inlines.silk_SMLAWB(a4, array2[num9 - 9], sPLC.prevLPC_Q12[8]); a4 = Inlines.silk_SMLAWB(a4, array2[num9 - 10], sPLC.prevLPC_Q12[9]); for (int k = 10; k < psDec.LPC_order; k++) { a4 = Inlines.silk_SMLAWB(a4, array2[num9 - k - 1], sPLC.prevLPC_Q12[k]); } array2[num9] = Inlines.silk_ADD_LSHIFT32(array2[num9], a4, 4); frame[frame_ptr + i] = (short)Inlines.silk_SAT16(Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(array2[num9], array3[1]), 8))); } Arrays.MemCopy(array2, num8 + psDec.frame_length, psDec.sLPC_Q14_buf, 0, 16); sPLC.rand_seed = num3; sPLC.randScale_Q14 = num2; for (int i = 0; i < 4; i++) { psDecCtrl.pitchL[i] = num4; } } internal static void silk_PLC_glue_frames(SilkChannelDecoder psDec, Span frame, int frame_ptr, int length) { PLCStruct sPLC = psDec.sPLC; if (psDec.lossCnt != 0) { SumSqrShift.silk_sum_sqr_shift(out sPLC.conc_energy, out sPLC.conc_energy_shift, frame, frame_ptr, length); sPLC.last_frame_lost = 1; return; } if (psDec.sPLC.last_frame_lost != 0) { SumSqrShift.silk_sum_sqr_shift(out var energy, out var shift, frame, frame_ptr, length); if (shift > sPLC.conc_energy_shift) { sPLC.conc_energy = Inlines.silk_RSHIFT(sPLC.conc_energy, shift - sPLC.conc_energy_shift); } else if (shift < sPLC.conc_energy_shift) { energy = Inlines.silk_RSHIFT(energy, sPLC.conc_energy_shift - shift); } if (energy > sPLC.conc_energy) { int num = Inlines.silk_CLZ32(sPLC.conc_energy); num--; sPLC.conc_energy = Inlines.silk_LSHIFT(sPLC.conc_energy, num); energy = Inlines.silk_RSHIFT(energy, Inlines.silk_max_32(24 - num, 0)); int num2 = Inlines.silk_LSHIFT(Inlines.silk_SQRT_APPROX(Inlines.silk_DIV32(sPLC.conc_energy, Inlines.silk_max(energy, 1))), 4); int a = Inlines.silk_DIV32_16(65536 - num2, length); a = Inlines.silk_LSHIFT(a, 2); for (int i = frame_ptr; i < frame_ptr + length; i++) { frame[i] = (short)Inlines.silk_SMULWB(num2, frame[i]); num2 += a; if (num2 > 65536) { break; } } } } sPLC.last_frame_lost = 0; } } internal static class ProcessGains { internal static void silk_process_gains(SilkChannelEncoder psEnc, SilkEncoderControl psEncCtrl, int condCoding) { SilkShapeState sShape = psEnc.sShape; if (psEnc.indices.signalType == 2) { int c = -Sigmoid.silk_sigm_Q15(Inlines.silk_RSHIFT_ROUND(psEncCtrl.LTPredCodGain_Q7 - 1536, 4)); for (int i = 0; i < psEnc.nb_subfr; i++) { psEncCtrl.Gains_Q16[i] = Inlines.silk_SMLAWB(psEncCtrl.Gains_Q16[i], psEncCtrl.Gains_Q16[i], c); } } int b = Inlines.silk_DIV32_16(Inlines.silk_log2lin(Inlines.silk_SMULWB(8894 - psEnc.SNR_dB_Q7, 21627)), psEnc.subfr_length); for (int i = 0; i < psEnc.nb_subfr; i++) { int num = Inlines.silk_SMULWW(psEncCtrl.ResNrg[i], b); num = ((psEncCtrl.ResNrgQ[i] > 0) ? Inlines.silk_RSHIFT_ROUND(num, psEncCtrl.ResNrgQ[i]) : ((num < Inlines.silk_RSHIFT(int.MaxValue, -psEncCtrl.ResNrgQ[i])) ? Inlines.silk_LSHIFT(num, -psEncCtrl.ResNrgQ[i]) : int.MaxValue)); int num2 = psEncCtrl.Gains_Q16[i]; int num3 = Inlines.silk_ADD_SAT32(num, Inlines.silk_SMMUL(num2, num2)); if (num3 < 32767) { num3 = Inlines.silk_SMLAWW(Inlines.silk_LSHIFT(num, 16), num2, num2); num2 = Inlines.silk_SQRT_APPROX(num3); num2 = Inlines.silk_min(num2, 8388607); psEncCtrl.Gains_Q16[i] = Inlines.silk_LSHIFT_SAT32(num2, 8); } else { num2 = Inlines.silk_SQRT_APPROX(num3); num2 = Inlines.silk_min(num2, 32767); psEncCtrl.Gains_Q16[i] = Inlines.silk_LSHIFT_SAT32(num2, 16); } } Arrays.MemCopy(psEncCtrl.Gains_Q16, 0, psEncCtrl.GainsUnq_Q16, 0, psEnc.nb_subfr); psEncCtrl.lastGainIndexPrev = sShape.LastGainIndex; BoxedValueSbyte boxedValueSbyte = new BoxedValueSbyte(sShape.LastGainIndex); GainQuantization.silk_gains_quant(psEnc.indices.GainsIndices, psEncCtrl.Gains_Q16, boxedValueSbyte, (condCoding == 2) ? 1 : 0, psEnc.nb_subfr); sShape.LastGainIndex = boxedValueSbyte.Val; if (psEnc.indices.signalType == 2) { if (psEncCtrl.LTPredCodGain_Q7 + Inlines.silk_RSHIFT(psEnc.input_tilt_Q15, 8) > 128) { psEnc.indices.quantOffsetType = 0; } else { psEnc.indices.quantOffsetType = 1; } } int b2 = Tables.silk_Quantization_Offsets_Q10[psEnc.indices.signalType >> 1][psEnc.indices.quantOffsetType]; psEncCtrl.Lambda_Q10 = 1229 + Inlines.silk_SMULBB(-50, psEnc.nStatesDelayedDecision) + Inlines.silk_SMULWB(-52428, psEnc.speech_activity_Q8) + Inlines.silk_SMULWB(-409, psEncCtrl.input_quality_Q14) + Inlines.silk_SMULWB(-818, psEncCtrl.coding_quality_Q14) + Inlines.silk_SMULWB(52429, b2); } } internal static class QuantizeLTPGains { internal static void silk_quant_LTP_gains(short[] B_Q14, sbyte[] cbk_index, BoxedValueSbyte periodicity_index, BoxedValueInt sum_log_gain_Q7, int[] W_Q18, int mu_Q9, int lowComplexity, int nb_subfr) { sbyte[] array = new sbyte[4]; int num = int.MaxValue; int val = 0; sbyte[][] cb_Q; for (int i = 0; i < 3; i++) { int num2 = 51; byte[] cl_Q = Tables.silk_LTP_gain_BITS_Q5_ptrs[i]; cb_Q = Tables.silk_LTP_vq_ptrs_Q7[i]; byte[] cb_gain_Q = Tables.silk_LTP_vq_gain_ptrs_Q7[i]; int l = Tables.silk_LTP_vq_sizes[i]; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = sum_log_gain_Q7.Val; for (int j = 0; j < nb_subfr; j++) { int max_gain_Q = Inlines.silk_log2lin(5333 - num6 + 896) - num2; BoxedValueSbyte boxedValueSbyte = new BoxedValueSbyte(array[j]); BoxedValueInt boxedValueInt = new BoxedValueInt(); BoxedValueInt boxedValueInt2 = new BoxedValueInt(); VQ_WMat_EC.silk_VQ_WMat_EC(boxedValueSbyte, boxedValueInt, boxedValueInt2, B_Q14, num4, W_Q18, num3, cb_Q, cb_gain_Q, cl_Q, mu_Q9, max_gain_Q, l); int val2 = boxedValueInt.Val; int val3 = boxedValueInt2.Val; array[j] = boxedValueSbyte.Val; num5 = Inlines.silk_ADD_POS_SAT32(num5, val2); num6 = Inlines.silk_max(0, num6 + Inlines.silk_lin2log(num2 + val3) - 896); num4 += 5; num3 += 25; } num5 = Inlines.silk_min(2147483646, num5); if (num5 < num) { num = num5; periodicity_index.Val = (sbyte)i; Arrays.MemCopy(array, 0, cbk_index, 0, nb_subfr); val = num6; } if (lowComplexity != 0 && num5 < Tables.silk_LTP_gain_middle_avg_RD_Q14) { break; } } cb_Q = Tables.silk_LTP_vq_ptrs_Q7[periodicity_index.Val]; for (int j = 0; j < nb_subfr; j++) { for (int i = 0; i < 5; i++) { B_Q14[j * 5 + i] = (short)Inlines.silk_LSHIFT(cb_Q[cbk_index[j]][i], 7); } } sum_log_gain_Q7.Val = val; } } internal static class RegularizeCorrelations { internal static void silk_regularize_correlations(int[] XX, int XX_ptr, int[] xx, int xx_ptr, int noise, int D) { for (int i = 0; i < D; i++) { Inlines.MatrixSet(XX, XX_ptr, i, i, D, Inlines.silk_ADD32(Inlines.MatrixGet(XX, XX_ptr, i, i, D), noise)); } xx[xx_ptr] += noise; } } internal static class Resampler { private const int USE_silk_resampler_copy = 0; private const int USE_silk_resampler_private_up2_HQ_wrapper = 1; private const int USE_silk_resampler_private_IIR_FIR = 2; private const int USE_silk_resampler_private_down_FIR = 3; private const int ORDER_FIR = 4; private static int rateID(int R) { return ((R >> 12) - ((R > 16000) ? 1 : 0) >> ((R > 24000) ? 1 : 0)) - 1; } internal static int silk_resampler_init(SilkResamplerState S, int Fs_Hz_in, int Fs_Hz_out, int forEnc) { S.Reset(); if (forEnc != 0) { if ((Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 && Fs_Hz_in != 24000 && Fs_Hz_in != 48000) || (Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000)) { return -1; } S.inputDelay = Tables.delay_matrix_enc[rateID(Fs_Hz_in), rateID(Fs_Hz_out)]; } else { if ((Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000) || (Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 && Fs_Hz_out != 24000 && Fs_Hz_out != 48000)) { return -1; } S.inputDelay = Tables.delay_matrix_dec[rateID(Fs_Hz_in), rateID(Fs_Hz_out)]; } S.Fs_in_kHz = Inlines.silk_DIV32_16(Fs_Hz_in, 1000); S.Fs_out_kHz = Inlines.silk_DIV32_16(Fs_Hz_out, 1000); S.batchSize = S.Fs_in_kHz * 10; int num = 0; if (Fs_Hz_out > Fs_Hz_in) { if (Fs_Hz_out == Inlines.silk_MUL(Fs_Hz_in, 2)) { S.resampler_function = 1; } else { S.resampler_function = 2; num = 1; } } else if (Fs_Hz_out < Fs_Hz_in) { S.resampler_function = 3; if (Inlines.silk_MUL(Fs_Hz_out, 4) == Inlines.silk_MUL(Fs_Hz_in, 3)) { S.FIR_Fracs = 3; S.FIR_Order = 18; S.Coefs = Tables.silk_Resampler_3_4_COEFS; } else if (Inlines.silk_MUL(Fs_Hz_out, 3) == Inlines.silk_MUL(Fs_Hz_in, 2)) { S.FIR_Fracs = 2; S.FIR_Order = 18; S.Coefs = Tables.silk_Resampler_2_3_COEFS; } else if (Inlines.silk_MUL(Fs_Hz_out, 2) == Fs_Hz_in) { S.FIR_Fracs = 1; S.FIR_Order = 24; S.Coefs = Tables.silk_Resampler_1_2_COEFS; } else if (Inlines.silk_MUL(Fs_Hz_out, 3) == Fs_Hz_in) { S.FIR_Fracs = 1; S.FIR_Order = 36; S.Coefs = Tables.silk_Resampler_1_3_COEFS; } else if (Inlines.silk_MUL(Fs_Hz_out, 4) == Fs_Hz_in) { S.FIR_Fracs = 1; S.FIR_Order = 36; S.Coefs = Tables.silk_Resampler_1_4_COEFS; } else { if (Inlines.silk_MUL(Fs_Hz_out, 6) != Fs_Hz_in) { return -1; } S.FIR_Fracs = 1; S.FIR_Order = 36; S.Coefs = Tables.silk_Resampler_1_6_COEFS; } } else { S.resampler_function = 0; } S.invRatio_Q16 = Inlines.silk_LSHIFT32(Inlines.silk_DIV32(Inlines.silk_LSHIFT32(Fs_Hz_in, 14 + num), Fs_Hz_out), 2); while (Inlines.silk_SMULWW(S.invRatio_Q16, Fs_Hz_out) < Inlines.silk_LSHIFT32(Fs_Hz_in, num)) { S.invRatio_Q16++; } return 0; } internal static int silk_resampler(SilkResamplerState S, Span output, int output_ptr, Span input, int input_ptr, int inLen) { int num = S.Fs_in_kHz - S.inputDelay; short[] delayBuf = S.delayBuf; input.Slice(input_ptr, num).CopyTo(delayBuf.AsSpan(S.inputDelay)); switch (S.resampler_function) { case 1: silk_resampler_private_up2_HQ(S.sIIR, output, output_ptr, delayBuf, 0, S.Fs_in_kHz); silk_resampler_private_up2_HQ(S.sIIR, output, output_ptr + S.Fs_out_kHz, input, input_ptr + num, inLen - S.Fs_in_kHz); break; case 2: silk_resampler_private_IIR_FIR(S, output, output_ptr, delayBuf, 0, S.Fs_in_kHz); silk_resampler_private_IIR_FIR(S, output, output_ptr + S.Fs_out_kHz, input, input_ptr + num, inLen - S.Fs_in_kHz); break; case 3: silk_resampler_private_down_FIR(S, output, output_ptr, delayBuf, 0, S.Fs_in_kHz); silk_resampler_private_down_FIR(S, output, output_ptr + S.Fs_out_kHz, input, input_ptr + num, inLen - S.Fs_in_kHz); break; default: delayBuf.AsSpan(0, S.Fs_in_kHz).CopyTo(output.Slice(output_ptr)); input.Slice(input_ptr + num, inLen - S.Fs_in_kHz).CopyTo(output.Slice(output_ptr + S.Fs_out_kHz)); break; } input.Slice(input_ptr + inLen - S.inputDelay, S.inputDelay).CopyTo(delayBuf); return SilkError.SILK_NO_ERROR; } internal static void silk_resampler_down2(int[] S, short[] output, short[] input, int inLen) { int num = Inlines.silk_RSHIFT32(inLen, 1); for (int i = 0; i < num; i++) { int a = Inlines.silk_LSHIFT(input[2 * i], 10); int num2 = Inlines.silk_SUB32(a, S[0]); int b = Inlines.silk_SMLAWB(num2, num2, -25727); int a2 = Inlines.silk_ADD32(S[0], b); S[0] = Inlines.silk_ADD32(a, b); a = Inlines.silk_LSHIFT(input[2 * i + 1], 10); b = Inlines.silk_SMULWB(Inlines.silk_SUB32(a, S[1]), 9872); a2 = Inlines.silk_ADD32(a2, S[1]); a2 = Inlines.silk_ADD32(a2, b); S[1] = Inlines.silk_ADD32(a, b); output[i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(a2, 11)); } } internal static void silk_resampler_down2_3(int[] S, short[] output, short[] input, int inLen) { int[] array = new int[484]; int num = 0; int num2 = 0; Arrays.MemCopy(S, 0, array, 0, 4); int num3; while (true) { num3 = Inlines.silk_min(inLen, 480); silk_resampler_private_AR2(S, 4, array, 4, input, num, Tables.silk_Resampler_2_3_COEFS_LQ, num3); int num4 = 0; for (int num5 = num3; num5 > 2; num5 -= 3) { int a = Inlines.silk_SMULWB(array[num4], Tables.silk_Resampler_2_3_COEFS_LQ[2]); a = Inlines.silk_SMLAWB(a, array[num4 + 1], Tables.silk_Resampler_2_3_COEFS_LQ[3]); a = Inlines.silk_SMLAWB(a, array[num4 + 2], Tables.silk_Resampler_2_3_COEFS_LQ[5]); a = Inlines.silk_SMLAWB(a, array[num4 + 3], Tables.silk_Resampler_2_3_COEFS_LQ[4]); output[num2++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(a, 6)); a = Inlines.silk_SMULWB(array[num4 + 1], Tables.silk_Resampler_2_3_COEFS_LQ[4]); a = Inlines.silk_SMLAWB(a, array[num4 + 2], Tables.silk_Resampler_2_3_COEFS_LQ[5]); a = Inlines.silk_SMLAWB(a, array[num4 + 3], Tables.silk_Resampler_2_3_COEFS_LQ[3]); a = Inlines.silk_SMLAWB(a, array[num4 + 4], Tables.silk_Resampler_2_3_COEFS_LQ[2]); output[num2++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(a, 6)); num4 += 3; } num += num3; inLen -= num3; if (inLen <= 0) { break; } Arrays.MemCopy(array, num3, array, 0, 4); } Arrays.MemCopy(array, num3, S, 0, 4); } internal static void silk_resampler_private_AR2(Span S, int S_ptr, Span out_Q8, int out_Q8_ptr, Span input, int input_ptr, short[] A_Q14, int len) { for (int i = 0; i < len; i++) { int num = Inlines.silk_ADD_LSHIFT32(S[S_ptr], input[input_ptr + i], 8); out_Q8[out_Q8_ptr + i] = num; num = Inlines.silk_LSHIFT(num, 2); S[S_ptr] = Inlines.silk_SMLAWB(S[S_ptr + 1], num, A_Q14[0]); S[S_ptr + 1] = Inlines.silk_SMULWB(num, A_Q14[1]); } } internal static int silk_resampler_private_down_FIR_INTERPOL(Span output, int output_ptr, int[] buf, Span FIR_Coefs, int FIR_Coefs_ptr, int FIR_Order, int FIR_Fracs, int max_index_Q16, int index_increment_Q16) { switch (FIR_Order) { case 18: { for (int i = 0; i < max_index_Q16; i += index_increment_Q16) { int num = Inlines.silk_RSHIFT(i, 16); int num2 = Inlines.silk_SMULWB(i & 0xFFFF, FIR_Fracs); int num3 = FIR_Coefs_ptr + 9 * num2; int a = Inlines.silk_SMULWB(buf[num], FIR_Coefs[num3]); a = Inlines.silk_SMLAWB(a, buf[num + 1], FIR_Coefs[num3 + 1]); a = Inlines.silk_SMLAWB(a, buf[num + 2], FIR_Coefs[num3 + 2]); a = Inlines.silk_SMLAWB(a, buf[num + 3], FIR_Coefs[num3 + 3]); a = Inlines.silk_SMLAWB(a, buf[num + 4], FIR_Coefs[num3 + 4]); a = Inlines.silk_SMLAWB(a, buf[num + 5], FIR_Coefs[num3 + 5]); a = Inlines.silk_SMLAWB(a, buf[num + 6], FIR_Coefs[num3 + 6]); a = Inlines.silk_SMLAWB(a, buf[num + 7], FIR_Coefs[num3 + 7]); a = Inlines.silk_SMLAWB(a, buf[num + 8], FIR_Coefs[num3 + 8]); num3 = FIR_Coefs_ptr + 9 * (FIR_Fracs - 1 - num2); a = Inlines.silk_SMLAWB(a, buf[num + 17], FIR_Coefs[num3]); a = Inlines.silk_SMLAWB(a, buf[num + 16], FIR_Coefs[num3 + 1]); a = Inlines.silk_SMLAWB(a, buf[num + 15], FIR_Coefs[num3 + 2]); a = Inlines.silk_SMLAWB(a, buf[num + 14], FIR_Coefs[num3 + 3]); a = Inlines.silk_SMLAWB(a, buf[num + 13], FIR_Coefs[num3 + 4]); a = Inlines.silk_SMLAWB(a, buf[num + 12], FIR_Coefs[num3 + 5]); a = Inlines.silk_SMLAWB(a, buf[num + 11], FIR_Coefs[num3 + 6]); a = Inlines.silk_SMLAWB(a, buf[num + 10], FIR_Coefs[num3 + 7]); a = Inlines.silk_SMLAWB(a, buf[num + 9], FIR_Coefs[num3 + 8]); output[output_ptr++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(a, 6)); } break; } case 24: { for (int i = 0; i < max_index_Q16; i += index_increment_Q16) { int num = Inlines.silk_RSHIFT(i, 16); int a = Inlines.silk_SMULWB(Inlines.silk_ADD32(buf[num], buf[num + 23]), FIR_Coefs[FIR_Coefs_ptr]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 1], buf[num + 22]), FIR_Coefs[FIR_Coefs_ptr + 1]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 2], buf[num + 21]), FIR_Coefs[FIR_Coefs_ptr + 2]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 3], buf[num + 20]), FIR_Coefs[FIR_Coefs_ptr + 3]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 4], buf[num + 19]), FIR_Coefs[FIR_Coefs_ptr + 4]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 5], buf[num + 18]), FIR_Coefs[FIR_Coefs_ptr + 5]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 6], buf[num + 17]), FIR_Coefs[FIR_Coefs_ptr + 6]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 7], buf[num + 16]), FIR_Coefs[FIR_Coefs_ptr + 7]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 8], buf[num + 15]), FIR_Coefs[FIR_Coefs_ptr + 8]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 9], buf[num + 14]), FIR_Coefs[FIR_Coefs_ptr + 9]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 10], buf[num + 13]), FIR_Coefs[FIR_Coefs_ptr + 10]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 11], buf[num + 12]), FIR_Coefs[FIR_Coefs_ptr + 11]); output[output_ptr++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(a, 6)); } break; } case 36: { for (int i = 0; i < max_index_Q16; i += index_increment_Q16) { int num = Inlines.silk_RSHIFT(i, 16); int a = Inlines.silk_SMULWB(Inlines.silk_ADD32(buf[num], buf[num + 35]), FIR_Coefs[FIR_Coefs_ptr]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 1], buf[num + 34]), FIR_Coefs[FIR_Coefs_ptr + 1]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 2], buf[num + 33]), FIR_Coefs[FIR_Coefs_ptr + 2]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 3], buf[num + 32]), FIR_Coefs[FIR_Coefs_ptr + 3]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 4], buf[num + 31]), FIR_Coefs[FIR_Coefs_ptr + 4]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 5], buf[num + 30]), FIR_Coefs[FIR_Coefs_ptr + 5]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 6], buf[num + 29]), FIR_Coefs[FIR_Coefs_ptr + 6]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 7], buf[num + 28]), FIR_Coefs[FIR_Coefs_ptr + 7]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 8], buf[num + 27]), FIR_Coefs[FIR_Coefs_ptr + 8]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 9], buf[num + 26]), FIR_Coefs[FIR_Coefs_ptr + 9]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 10], buf[num + 25]), FIR_Coefs[FIR_Coefs_ptr + 10]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 11], buf[num + 24]), FIR_Coefs[FIR_Coefs_ptr + 11]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 12], buf[num + 23]), FIR_Coefs[FIR_Coefs_ptr + 12]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 13], buf[num + 22]), FIR_Coefs[FIR_Coefs_ptr + 13]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 14], buf[num + 21]), FIR_Coefs[FIR_Coefs_ptr + 14]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 15], buf[num + 20]), FIR_Coefs[FIR_Coefs_ptr + 15]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 16], buf[num + 19]), FIR_Coefs[FIR_Coefs_ptr + 16]); a = Inlines.silk_SMLAWB(a, Inlines.silk_ADD32(buf[num + 17], buf[num + 18]), FIR_Coefs[FIR_Coefs_ptr + 17]); output[output_ptr++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(a, 6)); } break; } } return output_ptr; } internal static void silk_resampler_private_down_FIR(SilkResamplerState S, Span output, int output_ptr, Span input, int input_ptr, int inLen) { int[] array = new int[S.batchSize + S.FIR_Order]; Arrays.MemCopy(S.sFIR_i32, 0, array, 0, S.FIR_Order); int invRatio_Q = S.invRatio_Q16; int num; while (true) { num = Inlines.silk_min(inLen, S.batchSize); silk_resampler_private_AR2(S.sIIR, 0, array, S.FIR_Order, input, input_ptr, S.Coefs, num); int max_index_Q = Inlines.silk_LSHIFT32(num, 16); output_ptr = silk_resampler_private_down_FIR_INTERPOL(output, output_ptr, array, S.Coefs, 2, S.FIR_Order, S.FIR_Fracs, max_index_Q, invRatio_Q); input_ptr += num; inLen -= num; if (inLen <= 1) { break; } Arrays.MemCopy(array, num, array, 0, S.FIR_Order); } Arrays.MemCopy(array, num, S.sFIR_i32, 0, S.FIR_Order); } internal static int silk_resampler_private_IIR_FIR_INTERPOL(Span output, int output_ptr, short[] buf, int max_index_Q16, int index_increment_Q16) { for (int i = 0; i < max_index_Q16; i += index_increment_Q16) { int num = Inlines.silk_SMULWB(i & 0xFFFF, 12); int num2 = i >> 16; int a = Inlines.silk_SMULBB(buf[num2], Tables.silk_resampler_frac_FIR_12[num, 0]); a = Inlines.silk_SMLABB(a, buf[num2 + 1], Tables.silk_resampler_frac_FIR_12[num, 1]); a = Inlines.silk_SMLABB(a, buf[num2 + 2], Tables.silk_resampler_frac_FIR_12[num, 2]); a = Inlines.silk_SMLABB(a, buf[num2 + 3], Tables.silk_resampler_frac_FIR_12[num, 3]); a = Inlines.silk_SMLABB(a, buf[num2 + 4], Tables.silk_resampler_frac_FIR_12[11 - num, 3]); a = Inlines.silk_SMLABB(a, buf[num2 + 5], Tables.silk_resampler_frac_FIR_12[11 - num, 2]); a = Inlines.silk_SMLABB(a, buf[num2 + 6], Tables.silk_resampler_frac_FIR_12[11 - num, 1]); a = Inlines.silk_SMLABB(a, buf[num2 + 7], Tables.silk_resampler_frac_FIR_12[11 - num, 0]); output[output_ptr++] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(a, 15)); } return output_ptr; } internal static void silk_resampler_private_IIR_FIR(SilkResamplerState S, Span output, int output_ptr, Span input, int input_ptr, int inLen) { short[] array = new short[2 * S.batchSize + 8]; Arrays.MemCopy(S.sFIR_i16, 0, array, 0, 8); int invRatio_Q = S.invRatio_Q16; int num; while (true) { num = Inlines.silk_min(inLen, S.batchSize); silk_resampler_private_up2_HQ(S.sIIR, array, 8, input, input_ptr, num); int max_index_Q = Inlines.silk_LSHIFT32(num, 17); output_ptr = silk_resampler_private_IIR_FIR_INTERPOL(output, output_ptr, array, max_index_Q, invRatio_Q); input_ptr += num; inLen -= num; if (inLen <= 0) { break; } Arrays.MemCopy(array, num << 1, array, 0, 8); } Arrays.MemCopy(array, num << 1, S.sFIR_i16, 0, 8); } internal static void silk_resampler_private_up2_HQ(int[] S, Span output, int output_ptr, Span input, int input_ptr, int len) { for (int i = 0; i < len; i++) { int a = Inlines.silk_LSHIFT(input[input_ptr + i], 10); int b = Inlines.silk_SMULWB(Inlines.silk_SUB32(a, S[0]), Tables.silk_resampler_up2_hq_0[0]); int a2 = Inlines.silk_ADD32(S[0], b); S[0] = Inlines.silk_ADD32(a, b); b = Inlines.silk_SMULWB(Inlines.silk_SUB32(a2, S[1]), Tables.silk_resampler_up2_hq_0[1]); int a3 = Inlines.silk_ADD32(S[1], b); S[1] = Inlines.silk_ADD32(a2, b); int num = Inlines.silk_SUB32(a3, S[2]); b = Inlines.silk_SMLAWB(num, num, Tables.silk_resampler_up2_hq_0[2]); a2 = Inlines.silk_ADD32(S[2], b); S[2] = Inlines.silk_ADD32(a3, b); output[output_ptr + 2 * i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(a2, 10)); b = Inlines.silk_SMULWB(Inlines.silk_SUB32(a, S[3]), Tables.silk_resampler_up2_hq_1[0]); a2 = Inlines.silk_ADD32(S[3], b); S[3] = Inlines.silk_ADD32(a, b); b = Inlines.silk_SMULWB(Inlines.silk_SUB32(a2, S[4]), Tables.silk_resampler_up2_hq_1[1]); a3 = Inlines.silk_ADD32(S[4], b); S[4] = Inlines.silk_ADD32(a2, b); int num2 = Inlines.silk_SUB32(a3, S[5]); b = Inlines.silk_SMLAWB(num2, num2, Tables.silk_resampler_up2_hq_1[2]); a2 = Inlines.silk_ADD32(S[5], b); S[5] = Inlines.silk_ADD32(a3, b); output[output_ptr + 2 * i + 1] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(a2, 10)); } } } internal static class ResidualEnergy { internal static void silk_residual_energy(int[] nrgs, int[] nrgsQ, short[] x, short[][] a_Q12, int[] gains, int subfr_length, int nb_subfr, int LPC_order) { int num = 0; int num2 = LPC_order + subfr_length; short[] array = new short[2 * num2]; for (int i = 0; i < nb_subfr >> 1; i++) { Filters.silk_LPC_analysis_filter(array, 0, x, num, a_Q12[i], 0, 2 * num2, LPC_order); int num3 = LPC_order; for (int j = 0; j < 2; j++) { SumSqrShift.silk_sum_sqr_shift(out var energy, out var shift, array, num3, subfr_length); nrgs[i * 2 + j] = energy; nrgsQ[i * 2 + j] = -shift; num3 += num2; } num += 2 * num2; } for (int i = 0; i < nb_subfr; i++) { int num4 = Inlines.silk_CLZ32(nrgs[i]) - 1; int num5 = Inlines.silk_CLZ32(gains[i]) - 1; int num6 = Inlines.silk_LSHIFT32(gains[i], num5); num6 = Inlines.silk_SMMUL(num6, num6); nrgs[i] = Inlines.silk_SMMUL(num6, Inlines.silk_LSHIFT32(nrgs[i], num4)); nrgsQ[i] += num4 + 2 * num5 - 32 - 32; } } internal static int silk_residual_energy16_covar(short[] c, int c_ptr, int[] wXX, int wXX_ptr, int[] wXx, int wxx, int D, int cQ) { int[] array = new int[D]; int num = 16 - cQ; int a = num; int num2 = 0; for (int i = c_ptr; i < c_ptr + D; i++) { num2 = Inlines.silk_max_32(num2, Inlines.silk_abs(c[i])); } a = Inlines.silk_min_int(a, Inlines.silk_CLZ32(num2) - 17); int a2 = Inlines.silk_max_32(wXX[wXX_ptr], wXX[wXX_ptr + D * D - 1]); a = Inlines.silk_min_int(a, Inlines.silk_CLZ32(Inlines.silk_MUL(D, Inlines.silk_RSHIFT(Inlines.silk_SMULWB(a2, num2), 4))) - 5); a = Inlines.silk_max_int(a, 0); for (int i = 0; i < D; i++) { array[i] = Inlines.silk_LSHIFT(c[c_ptr + i], a); } num -= a; int num3 = 0; for (int i = 0; i < D; i++) { num3 = Inlines.silk_SMLAWB(num3, wXx[i], array[i]); } int a3 = Inlines.silk_RSHIFT(wxx, 1 + num) - num3; int num4 = 0; for (int i = 0; i < D; i++) { num3 = 0; int num5 = wXX_ptr + i * D; for (int j = i + 1; j < D; j++) { num3 = Inlines.silk_SMLAWB(num3, wXX[num5 + j], array[j]); } num3 = Inlines.silk_SMLAWB(num3, Inlines.silk_RSHIFT(wXX[num5 + i], 1), array[i]); num4 = Inlines.silk_SMLAWB(num4, num3, array[i]); } a3 = Inlines.silk_ADD_LSHIFT32(a3, num4, num); if (a3 < 1) { return 1; } if (a3 > Inlines.silk_RSHIFT(int.MaxValue, num + 2)) { return 1073741823; } return Inlines.silk_LSHIFT(a3, num + 1); } } internal static class Schur { internal static int silk_schur(short[] rc_Q15, int[] c, int order) { int[][] array = Arrays.InitTwoDimensionalArray(17, 2); int num = Inlines.silk_CLZ32(c[0]); int i; if (num < 2) { for (i = 0; i < order + 1; i++) { array[i][0] = (array[i][1] = Inlines.silk_RSHIFT(c[i], 1)); } } else if (num > 2) { num -= 2; for (i = 0; i < order + 1; i++) { array[i][0] = (array[i][1] = Inlines.silk_LSHIFT(c[i], num)); } } else { for (i = 0; i < order + 1; i++) { array[i][0] = (array[i][1] = c[i]); } } for (i = 0; i < order; i++) { if (Inlines.silk_abs_int32(array[i + 1][0]) >= array[0][1]) { if (array[i + 1][0] > 0) { rc_Q15[i] = -32440; } else { rc_Q15[i] = 32440; } i++; break; } int a = -Inlines.silk_DIV32_16(array[i + 1][0], Inlines.silk_max_32(Inlines.silk_RSHIFT(array[0][1], 15), 1)); a = Inlines.silk_SAT16(a); rc_Q15[i] = (short)a; for (int j = 0; j < order - i; j++) { int num2 = array[j + i + 1][0]; int num3 = array[j][1]; array[j + i + 1][0] = Inlines.silk_SMLAWB(num2, Inlines.silk_LSHIFT(num3, 1), a); array[j][1] = Inlines.silk_SMLAWB(num3, Inlines.silk_LSHIFT(num2, 1), a); } } for (; i < order; i++) { rc_Q15[i] = 0; } return Inlines.silk_max_32(1, array[0][1]); } internal static int silk_schur64(int[] rc_Q16, int[] c, int order) { int[][] array = Arrays.InitTwoDimensionalArray(17, 2); if (c[0] <= 0) { Arrays.MemSetInt(rc_Q16, 0, order); return 0; } int i; for (i = 0; i < order + 1; i++) { array[i][0] = (array[i][1] = c[i]); } for (i = 0; i < order; i++) { if (Inlines.silk_abs_int32(array[i + 1][0]) >= array[0][1]) { if (array[i + 1][0] > 0) { rc_Q16[i] = -64881; } else { rc_Q16[i] = 64881; } i++; break; } int num = Inlines.silk_DIV32_varQ(-array[i + 1][0], array[0][1], 31); rc_Q16[i] = Inlines.silk_RSHIFT_ROUND(num, 15); for (int j = 0; j < order - i; j++) { int num2 = array[j + i + 1][0]; int num3 = array[j][1]; array[j + i + 1][0] = num2 + Inlines.silk_SMMUL(Inlines.silk_LSHIFT(num3, 1), num); array[j][1] = num3 + Inlines.silk_SMMUL(Inlines.silk_LSHIFT(num2, 1), num); } } for (; i < order; i++) { rc_Q16[i] = 0; } return Inlines.silk_max_32(1, array[0][1]); } } internal static class ShellCoder { internal static void combine_pulses(int[] output, Span input, int input_ptr, int len) { for (int i = 0; i < len; i++) { output[i] = input[input_ptr + 2 * i] + input[input_ptr + 2 * i + 1]; } } internal static void combine_pulses(int[] output, int[] input, int len) { for (int i = 0; i < len; i++) { output[i] = input[2 * i] + input[2 * i + 1]; } } internal static void encode_split(EntropyCoder psRangeEnc, Span encodedData, int p_child1, int p, byte[] shell_table) { if (p > 0) { psRangeEnc.enc_icdf(encodedData, p_child1, shell_table, Tables.silk_shell_code_table_offsets[p], 8u); } } internal static void decode_split(short[] p_child1, int child1_ptr, Span p_child2, int p_child2_ptr, EntropyCoder psRangeDec, ReadOnlySpan encodedData, int p, byte[] shell_table) { if (p > 0) { p_child1[child1_ptr] = (short)psRangeDec.dec_icdf(encodedData, shell_table, Tables.silk_shell_code_table_offsets[p], 8u); p_child2[p_child2_ptr] = (short)(p - p_child1[child1_ptr]); } else { p_child1[child1_ptr] = 0; p_child2[p_child2_ptr] = 0; } } internal static void silk_shell_encoder(EntropyCoder psRangeEnc, Span encodedData, Span pulses0, int pulses0_ptr) { int[] array = new int[8]; int[] array2 = new int[4]; int[] array3 = new int[2]; int[] array4 = new int[1]; combine_pulses(array, pulses0, pulses0_ptr, 8); combine_pulses(array2, array, 4); combine_pulses(array3, array2, 2); combine_pulses(array4, array3, 1); encode_split(psRangeEnc, encodedData, array3[0], array4[0], Tables.silk_shell_code_table3); encode_split(psRangeEnc, encodedData, array2[0], array3[0], Tables.silk_shell_code_table2); encode_split(psRangeEnc, encodedData, array[0], array2[0], Tables.silk_shell_code_table1); encode_split(psRangeEnc, encodedData, pulses0[pulses0_ptr], array[0], Tables.silk_shell_code_table0); encode_split(psRangeEnc, encodedData, pulses0[pulses0_ptr + 2], array[1], Tables.silk_shell_code_table0); encode_split(psRangeEnc, encodedData, array[2], array2[1], Tables.silk_shell_code_table1); encode_split(psRangeEnc, encodedData, pulses0[pulses0_ptr + 4], array[2], Tables.silk_shell_code_table0); encode_split(psRangeEnc, encodedData, pulses0[pulses0_ptr + 6], array[3], Tables.silk_shell_code_table0); encode_split(psRangeEnc, encodedData, array2[2], array3[1], Tables.silk_shell_code_table2); encode_split(psRangeEnc, encodedData, array[4], array2[2], Tables.silk_shell_code_table1); encode_split(psRangeEnc, encodedData, pulses0[pulses0_ptr + 8], array[4], Tables.silk_shell_code_table0); encode_split(psRangeEnc, encodedData, pulses0[pulses0_ptr + 10], array[5], Tables.silk_shell_code_table0); encode_split(psRangeEnc, encodedData, array[6], array2[3], Tables.silk_shell_code_table1); encode_split(psRangeEnc, encodedData, pulses0[pulses0_ptr + 12], array[6], Tables.silk_shell_code_table0); encode_split(psRangeEnc, encodedData, pulses0[pulses0_ptr + 14], array[7], Tables.silk_shell_code_table0); } internal static void silk_shell_decoder(short[] pulses0, int pulses0_ptr, EntropyCoder psRangeDec, ReadOnlySpan encodedData, int pulses4) { short[] array = new short[8]; short[] array2 = new short[4]; short[] array3 = new short[2]; decode_split(array3, 0, array3, 1, psRangeDec, encodedData, pulses4, Tables.silk_shell_code_table3); decode_split(array2, 0, array2, 1, psRangeDec, encodedData, array3[0], Tables.silk_shell_code_table2); decode_split(array, 0, array, 1, psRangeDec, encodedData, array2[0], Tables.silk_shell_code_table1); decode_split(pulses0, pulses0_ptr, pulses0, pulses0_ptr + 1, psRangeDec, encodedData, array[0], Tables.silk_shell_code_table0); decode_split(pulses0, pulses0_ptr + 2, pulses0, pulses0_ptr + 3, psRangeDec, encodedData, array[1], Tables.silk_shell_code_table0); decode_split(array, 2, array, 3, psRangeDec, encodedData, array2[1], Tables.silk_shell_code_table1); decode_split(pulses0, pulses0_ptr + 4, pulses0, pulses0_ptr + 5, psRangeDec, encodedData, array[2], Tables.silk_shell_code_table0); decode_split(pulses0, pulses0_ptr + 6, pulses0, pulses0_ptr + 7, psRangeDec, encodedData, array[3], Tables.silk_shell_code_table0); decode_split(array2, 2, array2, 3, psRangeDec, encodedData, array3[1], Tables.silk_shell_code_table2); decode_split(array, 4, array, 5, psRangeDec, encodedData, array2[2], Tables.silk_shell_code_table1); decode_split(pulses0, pulses0_ptr + 8, pulses0, pulses0_ptr + 9, psRangeDec, encodedData, array[4], Tables.silk_shell_code_table0); decode_split(pulses0, pulses0_ptr + 10, pulses0, pulses0_ptr + 11, psRangeDec, encodedData, array[5], Tables.silk_shell_code_table0); decode_split(array, 6, array, 7, psRangeDec, encodedData, array2[3], Tables.silk_shell_code_table1); decode_split(pulses0, pulses0_ptr + 12, pulses0, pulses0_ptr + 13, psRangeDec, encodedData, array[6], Tables.silk_shell_code_table0); decode_split(pulses0, pulses0_ptr + 14, pulses0, pulses0_ptr + 15, psRangeDec, encodedData, array[7], Tables.silk_shell_code_table0); } } internal static class Sigmoid { private static readonly int[] sigm_LUT_slope_Q10 = new int[6] { 237, 153, 73, 30, 12, 7 }; private static readonly int[] sigm_LUT_pos_Q15 = new int[6] { 16384, 23955, 28861, 31213, 32178, 32548 }; private static readonly int[] sigm_LUT_neg_Q15 = new int[6] { 16384, 8812, 3906, 1554, 589, 219 }; internal static int silk_sigm_Q15(int in_Q5) { int num; if (in_Q5 < 0) { in_Q5 = -in_Q5; if (in_Q5 >= 192) { return 0; } num = Inlines.silk_RSHIFT(in_Q5, 5); return sigm_LUT_neg_Q15[num] - Inlines.silk_SMULBB(sigm_LUT_slope_Q10[num], in_Q5 & 0x1F); } if (in_Q5 >= 192) { return 32767; } num = Inlines.silk_RSHIFT(in_Q5, 5); return sigm_LUT_pos_Q15[num] + Inlines.silk_SMULBB(sigm_LUT_slope_Q10[num], in_Q5 & 0x1F); } } internal static class SilkConstants { internal const int ENCODER_NUM_CHANNELS = 2; internal const int DECODER_NUM_CHANNELS = 2; internal const int MAX_FRAMES_PER_PACKET = 3; internal const int MIN_TARGET_RATE_BPS = 5000; internal const int MAX_TARGET_RATE_BPS = 80000; internal const int TARGET_RATE_TAB_SZ = 8; internal const int LBRR_NB_MIN_RATE_BPS = 12000; internal const int LBRR_MB_MIN_RATE_BPS = 14000; internal const int LBRR_WB_MIN_RATE_BPS = 16000; internal const int NB_SPEECH_FRAMES_BEFORE_DTX = 10; internal const int MAX_CONSECUTIVE_DTX = 20; internal const int MAX_FS_KHZ = 16; internal const int MAX_API_FS_KHZ = 48; internal const int TYPE_NO_VOICE_ACTIVITY = 0; internal const int TYPE_UNVOICED = 1; internal const int TYPE_VOICED = 2; internal const int CODE_INDEPENDENTLY = 0; internal const int CODE_INDEPENDENTLY_NO_LTP_SCALING = 1; internal const int CODE_CONDITIONALLY = 2; internal const int STEREO_QUANT_TAB_SIZE = 16; internal const int STEREO_QUANT_SUB_STEPS = 5; internal const int STEREO_INTERP_LEN_MS = 8; internal const float STEREO_RATIO_SMOOTH_COEF = 0.01f; internal const int PITCH_EST_MIN_LAG_MS = 2; internal const int PITCH_EST_MAX_LAG_MS = 18; internal const int MAX_NB_SUBFR = 4; internal const int LTP_MEM_LENGTH_MS = 20; internal const int SUB_FRAME_LENGTH_MS = 5; internal const int MAX_SUB_FRAME_LENGTH = 80; internal const int MAX_FRAME_LENGTH_MS = 20; internal const int MAX_FRAME_LENGTH = 320; internal const int LA_PITCH_MS = 2; internal const int LA_PITCH_MAX = 32; internal const int MAX_FIND_PITCH_LPC_ORDER = 16; internal const int FIND_PITCH_LPC_WIN_MS = 24; internal const int FIND_PITCH_LPC_WIN_MS_2_SF = 14; internal const int FIND_PITCH_LPC_WIN_MAX = 384; internal const int LA_SHAPE_MS = 5; internal const int LA_SHAPE_MAX = 80; internal const int SHAPE_LPC_WIN_MAX = 240; internal const int MIN_QGAIN_DB = 2; internal const int MAX_QGAIN_DB = 88; internal const int N_LEVELS_QGAIN = 64; internal const int MAX_DELTA_GAIN_QUANT = 36; internal const int MIN_DELTA_GAIN_QUANT = -4; internal const short OFFSET_VL_Q10 = 32; internal const short OFFSET_VH_Q10 = 100; internal const short OFFSET_UVL_Q10 = 100; internal const short OFFSET_UVH_Q10 = 240; internal const int QUANT_LEVEL_ADJUST_Q10 = 80; internal const int MAX_LPC_STABILIZE_ITERATIONS = 16; internal const float MAX_PREDICTION_POWER_GAIN = 10000f; internal const float MAX_PREDICTION_POWER_GAIN_AFTER_RESET = 100f; internal const int SILK_MAX_ORDER_LPC = 16; internal const int MAX_LPC_ORDER = 16; internal const int MIN_LPC_ORDER = 10; internal const int LTP_ORDER = 5; internal const int NB_LTP_CBKS = 3; internal const int USE_HARM_SHAPING = 1; internal const int MAX_SHAPE_LPC_ORDER = 16; internal const int HARM_SHAPE_FIR_TAPS = 3; internal const int MAX_DEL_DEC_STATES = 4; internal const int LTP_BUF_LENGTH = 512; internal const int LTP_MASK = 511; internal const int DECISION_DELAY = 32; internal const int DECISION_DELAY_MASK = 31; internal const int SHELL_CODEC_FRAME_LENGTH = 16; internal const int LOG2_SHELL_CODEC_FRAME_LENGTH = 4; internal const int MAX_NB_SHELL_BLOCKS = 20; internal const int N_RATE_LEVELS = 10; internal const int SILK_MAX_PULSES = 16; internal const int MAX_MATRIX_SIZE = 16; internal static readonly int NSQ_LPC_BUF_LENGTH = Math.Max(16, 32); internal const int VAD_N_BANDS = 4; internal const int VAD_INTERNAL_SUBFRAMES_LOG2 = 2; internal const int VAD_INTERNAL_SUBFRAMES = 4; internal const int VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 = 1024; internal const int VAD_NOISE_LEVELS_BIAS = 50; internal const int VAD_NEGATIVE_OFFSET_Q5 = 128; internal const int VAD_SNR_FACTOR_Q16 = 45000; internal const int VAD_SNR_SMOOTH_COEF_Q18 = 4096; internal const int LSF_COS_TAB_SZ = 128; internal const int NLSF_W_Q = 2; internal const int NLSF_VQ_MAX_VECTORS = 32; internal const int NLSF_VQ_MAX_SURVIVORS = 32; internal const int NLSF_QUANT_MAX_AMPLITUDE = 4; internal const int NLSF_QUANT_MAX_AMPLITUDE_EXT = 10; internal const float NLSF_QUANT_LEVEL_ADJ = 0.1f; internal const int NLSF_QUANT_DEL_DEC_STATES_LOG2 = 2; internal const int NLSF_QUANT_DEL_DEC_STATES = 4; internal const int TRANSITION_TIME_MS = 5120; internal const int TRANSITION_NB = 3; internal const int TRANSITION_NA = 2; internal const int TRANSITION_INT_NUM = 5; internal const int TRANSITION_FRAMES = 256; internal const int TRANSITION_INT_STEPS = 64; internal const int BWE_AFTER_LOSS_Q16 = 63570; internal const int CNG_BUF_MASK_MAX = 255; internal const int CNG_GAIN_SMTH_Q16 = 4634; internal const int CNG_NLSF_SMTH_Q16 = 16348; internal const int PE_MAX_FS_KHZ = 16; internal const int PE_MAX_NB_SUBFR = 4; internal const int PE_SUBFR_LENGTH_MS = 5; internal const int PE_LTP_MEM_LENGTH_MS = 20; internal const int PE_MAX_FRAME_LENGTH_MS = 40; internal const int PE_MAX_FRAME_LENGTH = 640; internal const int PE_MAX_FRAME_LENGTH_ST_1 = 160; internal const int PE_MAX_FRAME_LENGTH_ST_2 = 320; internal const int PE_MAX_LAG_MS = 18; internal const int PE_MIN_LAG_MS = 2; internal const int PE_MAX_LAG = 288; internal const int PE_MIN_LAG = 32; internal const int PE_D_SRCH_LENGTH = 24; internal const int PE_NB_STAGE3_LAGS = 5; internal const int PE_NB_CBKS_STAGE2 = 3; internal const int PE_NB_CBKS_STAGE2_EXT = 11; internal const int PE_NB_CBKS_STAGE3_MAX = 34; internal const int PE_NB_CBKS_STAGE3_MID = 24; internal const int PE_NB_CBKS_STAGE3_MIN = 16; internal const int PE_NB_CBKS_STAGE3_10MS = 12; internal const int PE_NB_CBKS_STAGE2_10MS = 3; internal const float PE_SHORTLAG_BIAS = 0.2f; internal const float PE_PREVLAG_BIAS = 0.2f; internal const float PE_FLATCONTOUR_BIAS = 0.05f; internal const int SILK_PE_MIN_COMPLEX = 0; internal const int SILK_PE_MID_COMPLEX = 1; internal const int SILK_PE_MAX_COMPLEX = 2; internal const float BWE_COEF = 0.99f; internal const int V_PITCH_GAIN_START_MIN_Q14 = 11469; internal const int V_PITCH_GAIN_START_MAX_Q14 = 15565; internal const int MAX_PITCH_LAG_MS = 18; internal const int RAND_BUF_SIZE = 128; internal const int RAND_BUF_MASK = 127; internal const int LOG2_INV_LPC_GAIN_HIGH_THRES = 3; internal const int LOG2_INV_LPC_GAIN_LOW_THRES = 8; internal const int PITCH_DRIFT_FAC_Q16 = 655; internal const int SILK_RESAMPLER_MAX_FIR_ORDER = 36; internal const int SILK_RESAMPLER_MAX_IIR_ORDER = 6; internal const int RESAMPLER_DOWN_ORDER_FIR0 = 18; internal const int RESAMPLER_DOWN_ORDER_FIR1 = 24; internal const int RESAMPLER_DOWN_ORDER_FIR2 = 36; internal const int RESAMPLER_ORDER_FIR_12 = 8; internal const int RESAMPLER_MAX_BATCH_SIZE_MS = 10; internal const int RESAMPLER_MAX_FS_KHZ = 48; internal const int RESAMPLER_MAX_BATCH_SIZE_IN = 480; internal const int SILK_MAX_FRAMES_PER_PACKET = 3; } internal static class Sort { internal static void silk_insertion_sort_increasing(int[] a, int[] idx, int L, int K) { for (int i = 0; i < K; i++) { idx[i] = i; } for (int i = 1; i < K; i++) { int num = a[i]; int num2 = i - 1; while (num2 >= 0 && num < a[num2]) { a[num2 + 1] = a[num2]; idx[num2 + 1] = idx[num2]; num2--; } a[num2 + 1] = num; idx[num2 + 1] = i; } for (int i = K; i < L; i++) { int num = a[i]; if (num < a[K - 1]) { int num2 = K - 2; while (num2 >= 0 && num < a[num2]) { a[num2 + 1] = a[num2]; idx[num2 + 1] = idx[num2]; num2--; } a[num2 + 1] = num; idx[num2 + 1] = i; } } } internal static void silk_insertion_sort_increasing_all_values_int16(short[] a, int L) { for (int i = 1; i < L; i++) { short num = a[i]; int num2 = i - 1; while (num2 >= 0 && num < a[num2]) { a[num2 + 1] = a[num2]; num2--; } a[num2 + 1] = num; } } internal static void silk_insertion_sort_decreasing_int16(short[] a, int[] idx, int L, int K) { for (int i = 0; i < K; i++) { idx[i] = i; } for (int i = 1; i < K; i++) { short num = a[i]; int num2 = i - 1; while (num2 >= 0 && num > a[num2]) { a[num2 + 1] = a[num2]; idx[num2 + 1] = idx[num2]; num2--; } a[num2 + 1] = num; idx[num2 + 1] = i; } for (int i = K; i < L; i++) { short num = a[i]; if (num > a[K - 1]) { int num2 = K - 2; while (num2 >= 0 && num > a[num2]) { a[num2 + 1] = a[num2]; idx[num2 + 1] = idx[num2]; num2--; } a[num2 + 1] = num; idx[num2 + 1] = i; } } } } internal static class Stereo { internal static void silk_stereo_decode_pred(EntropyCoder psRangeDec, ReadOnlySpan encodedData, int[] pred_Q13) { int[][] array = Arrays.InitTwoDimensionalArray(2, 3); int num = psRangeDec.dec_icdf(encodedData, Tables.silk_stereo_pred_joint_iCDF, 8u); array[0][2] = Inlines.silk_DIV32_16(num, 5); array[1][2] = num - 5 * array[0][2]; for (num = 0; num < 2; num++) { array[num][0] = psRangeDec.dec_icdf(encodedData, Tables.silk_uniform3_iCDF, 8u); array[num][1] = psRangeDec.dec_icdf(encodedData, Tables.silk_uniform5_iCDF, 8u); } for (num = 0; num < 2; num++) { array[num][0] += 3 * array[num][2]; int num2 = Tables.silk_stereo_pred_quant_Q13[array[num][0]]; int b = Inlines.silk_SMULWB(Tables.silk_stereo_pred_quant_Q13[array[num][0] + 1] - num2, 6554); pred_Q13[num] = Inlines.silk_SMLABB(num2, b, 2 * array[num][1] + 1); } pred_Q13[0] -= pred_Q13[1]; } internal static void silk_stereo_decode_mid_only(EntropyCoder psRangeDec, ReadOnlySpan encodedData, BoxedValueInt decode_only_mid) { decode_only_mid.Val = psRangeDec.dec_icdf(encodedData, Tables.silk_stereo_only_code_mid_iCDF, 8u); } internal static void silk_stereo_encode_pred(EntropyCoder psRangeEnc, Span encodedData, sbyte[][] ix) { int s = 5 * ix[0][2] + ix[1][2]; psRangeEnc.enc_icdf(encodedData, s, Tables.silk_stereo_pred_joint_iCDF, 8u); for (s = 0; s < 2; s++) { psRangeEnc.enc_icdf(encodedData, ix[s][0], Tables.silk_uniform3_iCDF, 8u); psRangeEnc.enc_icdf(encodedData, ix[s][1], Tables.silk_uniform5_iCDF, 8u); } } internal static void silk_stereo_encode_mid_only(EntropyCoder psRangeEnc, Span encodedData, sbyte mid_only_flag) { psRangeEnc.enc_icdf(encodedData, mid_only_flag, Tables.silk_stereo_only_code_mid_iCDF, 8u); } internal static int silk_stereo_find_predictor(BoxedValueInt ratio_Q14, short[] x, short[] y, Span mid_res_amp_Q0, int mid_res_amp_Q0_ptr, int length, int smooth_coef_Q16) { SumSqrShift.silk_sum_sqr_shift(out var energy, out var shift, x, length); SumSqrShift.silk_sum_sqr_shift(out var energy2, out var shift2, y, length); int num = Inlines.silk_max_int(shift, shift2); num += num & 1; energy2 = Inlines.silk_RSHIFT32(energy2, num - shift2); energy = Inlines.silk_RSHIFT32(energy, num - shift); energy = Inlines.silk_max_int(energy, 1); int a = Inlines.silk_inner_prod_aligned_scale(x, y, num, length); int a2 = Inlines.silk_DIV32_varQ(a, energy, 13); a2 = Inlines.silk_LIMIT(a2, -16384, 16384); int num2 = Inlines.silk_SMULWB(a2, a2); smooth_coef_Q16 = Inlines.silk_max_int(smooth_coef_Q16, Inlines.silk_abs(num2)); num = Inlines.silk_RSHIFT(num, 1); mid_res_amp_Q0[mid_res_amp_Q0_ptr] = Inlines.silk_SMLAWB(mid_res_amp_Q0[mid_res_amp_Q0_ptr], Inlines.silk_LSHIFT(Inlines.silk_SQRT_APPROX(energy), num) - mid_res_amp_Q0[mid_res_amp_Q0_ptr], smooth_coef_Q16); energy2 = Inlines.silk_SUB_LSHIFT32(energy2, Inlines.silk_SMULWB(a, a2), 4); energy2 = Inlines.silk_ADD_LSHIFT32(energy2, Inlines.silk_SMULWB(energy, num2), 6); mid_res_amp_Q0[mid_res_amp_Q0_ptr + 1] = Inlines.silk_SMLAWB(mid_res_amp_Q0[mid_res_amp_Q0_ptr + 1], Inlines.silk_LSHIFT(Inlines.silk_SQRT_APPROX(energy2), num) - mid_res_amp_Q0[mid_res_amp_Q0_ptr + 1], smooth_coef_Q16); ratio_Q14.Val = Inlines.silk_DIV32_varQ(mid_res_amp_Q0[mid_res_amp_Q0_ptr + 1], Inlines.silk_max(mid_res_amp_Q0[mid_res_amp_Q0_ptr], 1), 14); ratio_Q14.Val = Inlines.silk_LIMIT(ratio_Q14.Val, 0, 32767); return a2; } internal static void silk_stereo_LR_to_MS(StereoEncodeState state, Span x1, int x1_ptr, Span x2, int x2_ptr, sbyte[][] ix, BoxedValueSbyte mid_only_flag, int[] mid_side_rates_bps, int total_rate_bps, int prev_speech_act_Q8, int toMono, int fs_kHz, int frame_length) { int[] array = new int[2]; BoxedValueInt boxedValueInt = new BoxedValueInt(); BoxedValueInt boxedValueInt2 = new BoxedValueInt(); int num = x1_ptr - 2; short[] array2 = new short[frame_length + 2]; for (int i = 0; i < frame_length + 2; i++) { int a = x1[x1_ptr + i - 2] + x2[x2_ptr + i - 2]; int a2 = x1[x1_ptr + i - 2] - x2[x2_ptr + i - 2]; x1[num + i] = (short)Inlines.silk_RSHIFT_ROUND(a, 1); array2[i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(a2, 1)); } state.sMid.AsSpan(0, 2).CopyTo(x1.Slice(num)); Arrays.MemCopy(state.sSide, 0, array2, 0, 2); x1.Slice(num + frame_length, 2).CopyTo(state.sMid); Arrays.MemCopy(array2, frame_length, state.sSide, 0, 2); short[] array3 = new short[frame_length]; short[] array4 = new short[frame_length]; for (int i = 0; i < frame_length; i++) { int a = Inlines.silk_RSHIFT_ROUND(Inlines.silk_ADD_LSHIFT32(x1[num + i] + x1[num + i + 2], x1[num + i + 1], 1), 2); array3[i] = (short)a; array4[i] = (short)(x1[num + i + 1] - a); } short[] array5 = new short[frame_length]; short[] array6 = new short[frame_length]; for (int i = 0; i < frame_length; i++) { int a = Inlines.silk_RSHIFT_ROUND(Inlines.silk_ADD_LSHIFT32(array2[i] + array2[i + 2], array2[i + 1], 1), 2); array5[i] = (short)a; array6[i] = (short)(array2[i + 1] - a); } int num2 = ((frame_length == 10 * fs_kHz) ? 1 : 0); int b = ((num2 != 0) ? 328 : 655); b = Inlines.silk_SMULWB(Inlines.silk_SMULBB(prev_speech_act_Q8, prev_speech_act_Q8), b); array[0] = silk_stereo_find_predictor(boxedValueInt, array3, array5, state.mid_side_amp_Q0, 0, frame_length, b); array[1] = silk_stereo_find_predictor(boxedValueInt2, array4, array6, state.mid_side_amp_Q0, 2, frame_length, b); int a3 = Inlines.silk_SMLABB(boxedValueInt2.Val, boxedValueInt.Val, 3); a3 = Inlines.silk_min(a3, 65536); total_rate_bps -= ((num2 != 0) ? 1200 : 600); if (total_rate_bps < 1) { total_rate_bps = 1; } int num3 = Inlines.silk_SMLABB(2000, fs_kHz, 900); int num4 = Inlines.silk_MUL(3, a3); mid_side_rates_bps[0] = Inlines.silk_DIV32_varQ(total_rate_bps, 851968 + num4, 19); int a4; if (mid_side_rates_bps[0] < num3) { mid_side_rates_bps[0] = num3; mid_side_rates_bps[1] = total_rate_bps - mid_side_rates_bps[0]; a4 = Inlines.silk_DIV32_varQ(Inlines.silk_LSHIFT(mid_side_rates_bps[1], 1) - num3, Inlines.silk_SMULWB(65536 + num4, num3), 16); a4 = Inlines.silk_LIMIT(a4, 0, 16384); } else { mid_side_rates_bps[1] = total_rate_bps - mid_side_rates_bps[0]; a4 = 16384; } state.smth_width_Q14 = (short)Inlines.silk_SMLAWB(state.smth_width_Q14, a4 - state.smth_width_Q14, b); mid_only_flag.Val = 0; if (toMono != 0) { a4 = 0; array[0] = 0; array[1] = 0; silk_stereo_quant_pred(array, ix); } else if (state.width_prev_Q14 == 0 && (8 * total_rate_bps < 13 * num3 || Inlines.silk_SMULWB(a3, state.smth_width_Q14) < 819)) { array[0] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, array[0]), 14); array[1] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, array[1]), 14); silk_stereo_quant_pred(array, ix); a4 = 0; array[0] = 0; array[1] = 0; mid_side_rates_bps[0] = total_rate_bps; mid_side_rates_bps[1] = 0; mid_only_flag.Val = 1; } else if (state.width_prev_Q14 != 0 && (8 * total_rate_bps < 11 * num3 || Inlines.silk_SMULWB(a3, state.smth_width_Q14) < 328)) { array[0] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, array[0]), 14); array[1] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, array[1]), 14); silk_stereo_quant_pred(array, ix); a4 = 0; array[0] = 0; array[1] = 0; } else if (state.smth_width_Q14 > 15565) { silk_stereo_quant_pred(array, ix); a4 = 16384; } else { array[0] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, array[0]), 14); array[1] = Inlines.silk_RSHIFT(Inlines.silk_SMULBB(state.smth_width_Q14, array[1]), 14); silk_stereo_quant_pred(array, ix); a4 = state.smth_width_Q14; } if (mid_only_flag.Val == 1) { state.silent_side_len += (short)(frame_length - 8 * fs_kHz); if (state.silent_side_len < 5 * fs_kHz) { mid_only_flag.Val = 0; } else { state.silent_side_len = 10000; } } else { state.silent_side_len = 0; } if (mid_only_flag.Val == 0 && mid_side_rates_bps[1] < 1) { mid_side_rates_bps[1] = 1; mid_side_rates_bps[0] = Inlines.silk_max_int(1, total_rate_bps - mid_side_rates_bps[1]); } int num5 = -state.pred_prev_Q13[0]; int num6 = -state.pred_prev_Q13[1]; int num7 = Inlines.silk_LSHIFT(state.width_prev_Q14, 10); int b2 = Inlines.silk_DIV32_16(65536, 8 * fs_kHz); int num8 = -Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULBB(array[0] - state.pred_prev_Q13[0], b2), 16); int num9 = -Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULBB(array[1] - state.pred_prev_Q13[1], b2), 16); int num10 = Inlines.silk_LSHIFT(Inlines.silk_SMULWB(a4 - state.width_prev_Q14, b2), 10); for (int i = 0; i < 8 * fs_kHz; i++) { num5 += num8; num6 += num9; num7 += num10; int a = Inlines.silk_LSHIFT(Inlines.silk_ADD_LSHIFT(x1[num + i] + x1[num + i + 2], x1[num + i + 1], 1), 9); a = Inlines.silk_SMLAWB(Inlines.silk_SMULWB(num7, array2[i + 1]), a, num5); a = Inlines.silk_SMLAWB(a, Inlines.silk_LSHIFT(x1[num + i + 1], 11), num6); x2[x2_ptr + i - 1] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(a, 8)); } num5 = -array[0]; num6 = -array[1]; num7 = Inlines.silk_LSHIFT(a4, 10); for (int i = 8 * fs_kHz; i < frame_length; i++) { int a = Inlines.silk_LSHIFT(Inlines.silk_ADD_LSHIFT(x1[num + i] + x1[num + i + 2], x1[num + i + 1], 1), 9); a = Inlines.silk_SMLAWB(Inlines.silk_SMULWB(num7, array2[i + 1]), a, num5); a = Inlines.silk_SMLAWB(a, Inlines.silk_LSHIFT(x1[num + i + 1], 11), num6); x2[x2_ptr + i - 1] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(a, 8)); } state.pred_prev_Q13[0] = (short)array[0]; state.pred_prev_Q13[1] = (short)array[1]; state.width_prev_Q14 = (short)a4; } internal static void silk_stereo_MS_to_LR(StereoDecodeState state, Span x1, int x1_ptr, Span x2, int x2_ptr, int[] pred_Q13, int fs_kHz, int frame_length) { state.sMid.AsSpan(0, 2).CopyTo(x1.Slice(x1_ptr)); state.sSide.AsSpan(0, 2).CopyTo(x2.Slice(x2_ptr)); x1.Slice(x1_ptr + frame_length, 2).CopyTo(state.sMid); x2.Slice(x2_ptr + frame_length, 2).CopyTo(state.sSide); int num = state.pred_prev_Q13[0]; int num2 = state.pred_prev_Q13[1]; int b = Inlines.silk_DIV32_16(65536, 8 * fs_kHz); int num3 = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULBB(pred_Q13[0] - state.pred_prev_Q13[0], b), 16); int num4 = Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULBB(pred_Q13[1] - state.pred_prev_Q13[1], b), 16); for (int i = 0; i < 8 * fs_kHz; i++) { num += num3; num2 += num4; int b2 = Inlines.silk_LSHIFT(Inlines.silk_ADD_LSHIFT(x1[x1_ptr + i] + x1[x1_ptr + i + 2], x1[x1_ptr + i + 1], 1), 9); b2 = Inlines.silk_SMLAWB(Inlines.silk_LSHIFT(x2[x2_ptr + i + 1], 8), b2, num); b2 = Inlines.silk_SMLAWB(b2, Inlines.silk_LSHIFT(x1[x1_ptr + i + 1], 11), num2); x2[x2_ptr + i + 1] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(b2, 8)); } num = pred_Q13[0]; num2 = pred_Q13[1]; for (int i = 8 * fs_kHz; i < frame_length; i++) { int b2 = Inlines.silk_LSHIFT(Inlines.silk_ADD_LSHIFT(x1[x1_ptr + i] + x1[x1_ptr + i + 2], x1[x1_ptr + i + 1], 1), 9); b2 = Inlines.silk_SMLAWB(Inlines.silk_LSHIFT(x2[x2_ptr + i + 1], 8), b2, num); b2 = Inlines.silk_SMLAWB(b2, Inlines.silk_LSHIFT(x1[x1_ptr + i + 1], 11), num2); x2[x2_ptr + i + 1] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(b2, 8)); } state.pred_prev_Q13[0] = (short)pred_Q13[0]; state.pred_prev_Q13[1] = (short)pred_Q13[1]; for (int i = 0; i < frame_length; i++) { int b2 = x1[x1_ptr + i + 1] + x2[x2_ptr + i + 1]; int a = x1[x1_ptr + i + 1] - x2[x2_ptr + i + 1]; x1[x1_ptr + i + 1] = (short)Inlines.silk_SAT16(b2); x2[x2_ptr + i + 1] = (short)Inlines.silk_SAT16(a); } } internal static void silk_stereo_quant_pred(int[] pred_Q13, sbyte[][] ix) { int num = 0; Arrays.MemSetSbyte(ix[0], 0, 3); Arrays.MemSetSbyte(ix[1], 0, 3); for (int i = 0; i < 2; i++) { int num2 = int.MaxValue; sbyte b = 0; while (b < 15) { int num3 = Tables.silk_stereo_pred_quant_Q13[b]; int b2 = Inlines.silk_SMULWB(Tables.silk_stereo_pred_quant_Q13[b + 1] - num3, 6554); for (sbyte b3 = 0; b3 < 5; b3++) { int num4 = Inlines.silk_SMLABB(num3, b2, 2 * b3 + 1); int num5 = Inlines.silk_abs(pred_Q13[i] - num4); if (num5 >= num2) { goto end_IL_0090; } num2 = num5; num = num4; ix[i][0] = b; ix[i][1] = b3; } b++; continue; end_IL_0090: break; } ix[i][2] = (sbyte)Inlines.silk_DIV32_16(ix[i][0], 3); ix[i][0] = (sbyte)(ix[i][0] - (sbyte)(ix[i][2] * 3)); pred_Q13[i] = num; } pred_Q13[0] -= pred_Q13[1]; } } internal static class SumSqrShift { internal static void silk_sum_sqr_shift(out int energy, out int shift, Span x, int x_ptr, int len) { int num = 0; int num2 = 0; len--; int i; for (i = 0; i < len; i += 2) { num = Inlines.silk_SMLABB_ovflw(num, x[x_ptr + i], x[x_ptr + i]); num = Inlines.silk_SMLABB_ovflw(num, x[x_ptr + i + 1], x[x_ptr + i + 1]); if (num < 0) { num = (int)Inlines.silk_RSHIFT_uint((uint)num, 2); num2 = 2; i += 2; break; } } for (; i < len; i += 2) { int a = Inlines.silk_SMULBB(x[x_ptr + i], x[x_ptr + i]); a = Inlines.silk_SMLABB_ovflw(a, x[x_ptr + i + 1], x[x_ptr + i + 1]); num = (int)Inlines.silk_ADD_RSHIFT_uint((uint)num, (uint)a, num2); if (num < 0) { num = (int)Inlines.silk_RSHIFT_uint((uint)num, 2); num2 += 2; } } if (i == len) { int a = Inlines.silk_SMULBB(x[x_ptr + i], x[x_ptr + i]); num = (int)Inlines.silk_ADD_RSHIFT_uint((uint)num, (uint)a, num2); } if ((num & 0xC0000000u) != 0L) { num = (int)Inlines.silk_RSHIFT_uint((uint)num, 2); num2 += 2; } shift = num2; energy = num; } internal static void silk_sum_sqr_shift(out int energy, out int shift, short[] x, int len) { int num = 0; int num2 = 0; len--; int i; for (i = 0; i < len; i += 2) { num = Inlines.silk_SMLABB_ovflw(num, x[i], x[i]); num = Inlines.silk_SMLABB_ovflw(num, x[i + 1], x[i + 1]); if (num < 0) { num = (int)Inlines.silk_RSHIFT_uint((uint)num, 2); num2 = 2; i += 2; break; } } for (; i < len; i += 2) { int a = Inlines.silk_SMULBB(x[i], x[i]); a = Inlines.silk_SMLABB_ovflw(a, x[i + 1], x[i + 1]); num = (int)Inlines.silk_ADD_RSHIFT_uint((uint)num, (uint)a, num2); if (num < 0) { num = (int)Inlines.silk_RSHIFT_uint((uint)num, 2); num2 += 2; } } if (i == len) { int a = Inlines.silk_SMULBB(x[i], x[i]); num = (int)Inlines.silk_ADD_RSHIFT_uint((uint)num, (uint)a, num2); } if ((num & 0xC0000000u) != 0L) { num = (int)Inlines.silk_RSHIFT_uint((uint)num, 2); num2 += 2; } shift = num2; energy = num; } } internal static class Tables { internal static readonly short[] silk_LSFCosTab_Q12 = new short[129] { 8192, 8190, 8182, 8170, 8152, 8130, 8104, 8072, 8034, 7994, 7946, 7896, 7840, 7778, 7714, 7644, 7568, 7490, 7406, 7318, 7226, 7128, 7026, 6922, 6812, 6698, 6580, 6458, 6332, 6204, 6070, 5934, 5792, 5648, 5502, 5352, 5198, 5040, 4880, 4718, 4552, 4382, 4212, 4038, 3862, 3684, 3502, 3320, 3136, 2948, 2760, 2570, 2378, 2186, 1990, 1794, 1598, 1400, 1202, 1002, 802, 602, 402, 202, 0, -202, -402, -602, -802, -1002, -1202, -1400, -1598, -1794, -1990, -2186, -2378, -2570, -2760, -2948, -3136, -3320, -3502, -3684, -3862, -4038, -4212, -4382, -4552, -4718, -4880, -5040, -5198, -5352, -5502, -5648, -5792, -5934, -6070, -6204, -6332, -6458, -6580, -6698, -6812, -6922, -7026, -7128, -7226, -7318, -7406, -7490, -7568, -7644, -7714, -7778, -7840, -7896, -7946, -7994, -8034, -8072, -8104, -8130, -8152, -8170, -8182, -8190, -8192 }; internal static readonly byte[][] silk_gain_iCDF = new byte[3][] { new byte[8] { 224, 112, 44, 15, 3, 2, 1, 0 }, new byte[8] { 254, 237, 192, 132, 70, 23, 4, 0 }, new byte[8] { 255, 252, 226, 155, 61, 11, 2, 0 } }; internal static readonly byte[] silk_delta_gain_iCDF = new byte[41] { 250, 245, 234, 203, 71, 50, 42, 38, 35, 33, 31, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; internal static readonly byte[] silk_LTP_per_index_iCDF = new byte[3] { 179, 99, 0 }; internal static readonly byte[] silk_LTP_gain_iCDF_0 = new byte[8] { 71, 56, 43, 30, 21, 12, 6, 0 }; internal static readonly byte[] silk_LTP_gain_iCDF_1 = new byte[16] { 199, 165, 144, 124, 109, 96, 84, 71, 61, 51, 42, 32, 23, 15, 8, 0 }; internal static readonly byte[] silk_LTP_gain_iCDF_2 = new byte[32] { 241, 225, 211, 199, 187, 175, 164, 153, 142, 132, 123, 114, 105, 96, 88, 80, 72, 64, 57, 50, 44, 38, 33, 29, 24, 20, 16, 12, 9, 5, 2, 0 }; internal static readonly short silk_LTP_gain_middle_avg_RD_Q14 = 12304; internal static readonly byte[] silk_LTP_gain_BITS_Q5_0 = new byte[8] { 15, 131, 138, 138, 155, 155, 173, 173 }; internal static readonly byte[] silk_LTP_gain_BITS_Q5_1 = new byte[16] { 69, 93, 115, 118, 131, 138, 141, 138, 150, 150, 155, 150, 155, 160, 166, 160 }; internal static readonly byte[] silk_LTP_gain_BITS_Q5_2 = new byte[32] { 131, 128, 134, 141, 141, 141, 145, 145, 145, 150, 155, 155, 155, 155, 160, 160, 160, 160, 166, 166, 173, 173, 182, 192, 182, 192, 192, 192, 205, 192, 205, 224 }; internal static readonly byte[][] silk_LTP_gain_iCDF_ptrs = new byte[3][] { silk_LTP_gain_iCDF_0, silk_LTP_gain_iCDF_1, silk_LTP_gain_iCDF_2 }; internal static readonly byte[][] silk_LTP_gain_BITS_Q5_ptrs = new byte[3][] { silk_LTP_gain_BITS_Q5_0, silk_LTP_gain_BITS_Q5_1, silk_LTP_gain_BITS_Q5_2 }; internal static readonly sbyte[][] silk_LTP_gain_vq_0 = new sbyte[8][] { new sbyte[5] { 4, 6, 24, 7, 5 }, new sbyte[5] { 0, 0, 2, 0, 0 }, new sbyte[5] { 12, 28, 41, 13, -4 }, new sbyte[5] { -9, 15, 42, 25, 14 }, new sbyte[5] { 1, -2, 62, 41, -9 }, new sbyte[5] { -10, 37, 65, -4, 3 }, new sbyte[5] { -6, 4, 66, 7, -8 }, new sbyte[5] { 16, 14, 38, -3, 33 } }; internal static readonly sbyte[][] silk_LTP_gain_vq_1 = new sbyte[16][] { new sbyte[5] { 13, 22, 39, 23, 12 }, new sbyte[5] { -1, 36, 64, 27, -6 }, new sbyte[5] { -7, 10, 55, 43, 17 }, new sbyte[5] { 1, 1, 8, 1, 1 }, new sbyte[5] { 6, -11, 74, 53, -9 }, new sbyte[5] { -12, 55, 76, -12, 8 }, new sbyte[5] { -3, 3, 93, 27, -4 }, new sbyte[5] { 26, 39, 59, 3, -8 }, new sbyte[5] { 2, 0, 77, 11, 9 }, new sbyte[5] { -8, 22, 44, -6, 7 }, new sbyte[5] { 40, 9, 26, 3, 9 }, new sbyte[5] { -7, 20, 101, -7, 4 }, new sbyte[5] { 3, -8, 42, 26, 0 }, new sbyte[5] { -15, 33, 68, 2, 23 }, new sbyte[5] { -2, 55, 46, -2, 15 }, new sbyte[5] { 3, -1, 21, 16, 41 } }; internal static readonly sbyte[][] silk_LTP_gain_vq_2 = new sbyte[32][] { new sbyte[5] { -6, 27, 61, 39, 5 }, new sbyte[5] { -11, 42, 88, 4, 1 }, new sbyte[5] { -2, 60, 65, 6, -4 }, new sbyte[5] { -1, -5, 73, 56, 1 }, new sbyte[5] { -9, 19, 94, 29, -9 }, new sbyte[5] { 0, 12, 99, 6, 4 }, new sbyte[5] { 8, -19, 102, 46, -13 }, new sbyte[5] { 3, 2, 13, 3, 2 }, new sbyte[5] { 9, -21, 84, 72, -18 }, new sbyte[5] { -11, 46, 104, -22, 8 }, new sbyte[5] { 18, 38, 48, 23, 0 }, new sbyte[5] { -16, 70, 83, -21, 11 }, new sbyte[5] { 5, -11, 117, 22, -8 }, new sbyte[5] { -6, 23, 117, -12, 3 }, new sbyte[5] { 3, -8, 95, 28, 4 }, new sbyte[5] { -10, 15, 77, 60, -15 }, new sbyte[5] { -1, 4, 124, 2, -4 }, new sbyte[5] { 3, 38, 84, 24, -25 }, new sbyte[5] { 2, 13, 42, 13, 31 }, new sbyte[5] { 21, -4, 56, 46, -1 }, new sbyte[5] { -1, 35, 79, -13, 19 }, new sbyte[5] { -7, 65, 88, -9, -14 }, new sbyte[5] { 20, 4, 81, 49, -29 }, new sbyte[5] { 20, 0, 75, 3, -17 }, new sbyte[5] { 5, -9, 44, 92, -8 }, new sbyte[5] { 1, -3, 22, 69, 31 }, new sbyte[5] { -6, 95, 41, -12, 5 }, new sbyte[5] { 39, 67, 16, -4, 1 }, new sbyte[5] { 0, -6, 120, 55, -36 }, new sbyte[5] { -13, 44, 122, 4, -24 }, new sbyte[5] { 81, 5, 11, 3, 7 }, new sbyte[5] { 2, 0, 9, 10, 88 } }; internal static readonly sbyte[][][] silk_LTP_vq_ptrs_Q7 = new sbyte[3][][] { silk_LTP_gain_vq_0, silk_LTP_gain_vq_1, silk_LTP_gain_vq_2 }; internal static readonly byte[] silk_LTP_gain_vq_0_gain = new byte[8] { 46, 2, 90, 87, 93, 91, 82, 98 }; internal static readonly byte[] silk_LTP_gain_vq_1_gain = new byte[16] { 109, 120, 118, 12, 113, 115, 117, 119, 99, 59, 87, 111, 63, 111, 112, 80 }; internal static readonly byte[] silk_LTP_gain_vq_2_gain = new byte[32] { 126, 124, 125, 124, 129, 121, 126, 23, 132, 127, 127, 127, 126, 127, 122, 133, 130, 134, 101, 118, 119, 145, 126, 86, 124, 120, 123, 119, 170, 173, 107, 109 }; internal static readonly byte[][] silk_LTP_vq_gain_ptrs_Q7 = new byte[3][] { silk_LTP_gain_vq_0_gain, silk_LTP_gain_vq_1_gain, silk_LTP_gain_vq_2_gain }; internal static readonly sbyte[] silk_LTP_vq_sizes = new sbyte[3] { 8, 16, 32 }; internal static readonly byte[] silk_NLSF_CB1_NB_MB_Q8 = new byte[320] { 12, 35, 60, 83, 108, 132, 157, 180, 206, 228, 15, 32, 55, 77, 101, 125, 151, 175, 201, 225, 19, 42, 66, 89, 114, 137, 162, 184, 209, 230, 12, 25, 50, 72, 97, 120, 147, 172, 200, 223, 26, 44, 69, 90, 114, 135, 159, 180, 205, 225, 13, 22, 53, 80, 106, 130, 156, 180, 205, 228, 15, 25, 44, 64, 90, 115, 142, 168, 196, 222, 19, 24, 62, 82, 100, 120, 145, 168, 190, 214, 22, 31, 50, 79, 103, 120, 151, 170, 203, 227, 21, 29, 45, 65, 106, 124, 150, 171, 196, 224, 30, 49, 75, 97, 121, 142, 165, 186, 209, 229, 19, 25, 52, 70, 93, 116, 143, 166, 192, 219, 26, 34, 62, 75, 97, 118, 145, 167, 194, 217, 25, 33, 56, 70, 91, 113, 143, 165, 196, 223, 21, 34, 51, 72, 97, 117, 145, 171, 196, 222, 20, 29, 50, 67, 90, 117, 144, 168, 197, 221, 22, 31, 48, 66, 95, 117, 146, 168, 196, 222, 24, 33, 51, 77, 116, 134, 158, 180, 200, 224, 21, 28, 70, 87, 106, 124, 149, 170, 194, 217, 26, 33, 53, 64, 83, 117, 152, 173, 204, 225, 27, 34, 65, 95, 108, 129, 155, 174, 210, 225, 20, 26, 72, 99, 113, 131, 154, 176, 200, 219, 34, 43, 61, 78, 93, 114, 155, 177, 205, 229, 23, 29, 54, 97, 124, 138, 163, 179, 209, 229, 30, 38, 56, 89, 118, 129, 158, 178, 200, 231, 21, 29, 49, 63, 85, 111, 142, 163, 193, 222, 27, 48, 77, 103, 133, 158, 179, 196, 215, 232, 29, 47, 74, 99, 124, 151, 176, 198, 220, 237, 33, 42, 61, 76, 93, 121, 155, 174, 207, 225, 29, 53, 87, 112, 136, 154, 170, 188, 208, 227, 24, 30, 52, 84, 131, 150, 166, 186, 203, 229, 37, 48, 64, 84, 104, 118, 156, 177, 201, 230 }; internal static readonly byte[] silk_NLSF_CB1_iCDF_NB_MB = new byte[64] { 212, 178, 148, 129, 108, 96, 85, 82, 79, 77, 61, 59, 57, 56, 51, 49, 48, 45, 42, 41, 40, 38, 36, 34, 31, 30, 21, 12, 10, 3, 1, 0, 255, 245, 244, 236, 233, 225, 217, 203, 190, 176, 175, 161, 149, 136, 125, 114, 102, 91, 81, 71, 60, 52, 43, 35, 28, 20, 19, 18, 12, 11, 5, 0 }; internal static readonly byte[] silk_NLSF_CB2_SELECT_NB_MB = new byte[160] { 16, 0, 0, 0, 0, 99, 66, 36, 36, 34, 36, 34, 34, 34, 34, 83, 69, 36, 52, 34, 116, 102, 70, 68, 68, 176, 102, 68, 68, 34, 65, 85, 68, 84, 36, 116, 141, 152, 139, 170, 132, 187, 184, 216, 137, 132, 249, 168, 185, 139, 104, 102, 100, 68, 68, 178, 218, 185, 185, 170, 244, 216, 187, 187, 170, 244, 187, 187, 219, 138, 103, 155, 184, 185, 137, 116, 183, 155, 152, 136, 132, 217, 184, 184, 170, 164, 217, 171, 155, 139, 244, 169, 184, 185, 170, 164, 216, 223, 218, 138, 214, 143, 188, 218, 168, 244, 141, 136, 155, 170, 168, 138, 220, 219, 139, 164, 219, 202, 216, 137, 168, 186, 246, 185, 139, 116, 185, 219, 185, 138, 100, 100, 134, 100, 102, 34, 68, 68, 100, 68, 168, 203, 221, 218, 168, 167, 154, 136, 104, 70, 164, 246, 171, 137, 139, 137, 155, 218, 219, 139 }; internal static readonly byte[] silk_NLSF_CB2_iCDF_NB_MB = new byte[72] { 255, 254, 253, 238, 14, 3, 2, 1, 0, 255, 254, 252, 218, 35, 3, 2, 1, 0, 255, 254, 250, 208, 59, 4, 2, 1, 0, 255, 254, 246, 194, 71, 10, 2, 1, 0, 255, 252, 236, 183, 82, 8, 2, 1, 0, 255, 252, 235, 180, 90, 17, 2, 1, 0, 255, 248, 224, 171, 97, 30, 4, 1, 0, 255, 254, 236, 173, 95, 37, 7, 1, 0 }; internal static readonly byte[] silk_NLSF_CB2_BITS_NB_MB_Q5 = new byte[72] { 255, 255, 255, 131, 6, 145, 255, 255, 255, 255, 255, 236, 93, 15, 96, 255, 255, 255, 255, 255, 194, 83, 25, 71, 221, 255, 255, 255, 255, 162, 73, 34, 66, 162, 255, 255, 255, 210, 126, 73, 43, 57, 173, 255, 255, 255, 201, 125, 71, 48, 58, 130, 255, 255, 255, 166, 110, 73, 57, 62, 104, 210, 255, 255, 251, 123, 65, 55, 68, 100, 171, 255 }; internal static readonly byte[] silk_NLSF_PRED_NB_MB_Q8 = new byte[18] { 179, 138, 140, 148, 151, 149, 153, 151, 163, 116, 67, 82, 59, 92, 72, 100, 89, 92 }; internal static readonly short[] silk_NLSF_DELTA_MIN_NB_MB_Q15 = new short[11] { 250, 3, 6, 3, 3, 3, 4, 3, 3, 3, 461 }; internal static readonly NLSFCodebook silk_NLSF_CB_NB_MB = new NLSFCodebook { nVectors = 32, order = 10, quantStepSize_Q16 = 11796, invQuantStepSize_Q6 = 356, CB1_NLSF_Q8 = silk_NLSF_CB1_NB_MB_Q8, CB1_iCDF = silk_NLSF_CB1_iCDF_NB_MB, pred_Q8 = silk_NLSF_PRED_NB_MB_Q8, ec_sel = silk_NLSF_CB2_SELECT_NB_MB, ec_iCDF = silk_NLSF_CB2_iCDF_NB_MB, ec_Rates_Q5 = silk_NLSF_CB2_BITS_NB_MB_Q5, deltaMin_Q15 = silk_NLSF_DELTA_MIN_NB_MB_Q15 }; internal static readonly byte[] silk_NLSF_CB1_WB_Q8 = new byte[512] { 7, 23, 38, 54, 69, 85, 100, 116, 131, 147, 162, 178, 193, 208, 223, 239, 13, 25, 41, 55, 69, 83, 98, 112, 127, 142, 157, 171, 187, 203, 220, 236, 15, 21, 34, 51, 61, 78, 92, 106, 126, 136, 152, 167, 185, 205, 225, 240, 10, 21, 36, 50, 63, 79, 95, 110, 126, 141, 157, 173, 189, 205, 221, 237, 17, 20, 37, 51, 59, 78, 89, 107, 123, 134, 150, 164, 184, 205, 224, 240, 10, 15, 32, 51, 67, 81, 96, 112, 129, 142, 158, 173, 189, 204, 220, 236, 8, 21, 37, 51, 65, 79, 98, 113, 126, 138, 155, 168, 179, 192, 209, 218, 12, 15, 34, 55, 63, 78, 87, 108, 118, 131, 148, 167, 185, 203, 219, 236, 16, 19, 32, 36, 56, 79, 91, 108, 118, 136, 154, 171, 186, 204, 220, 237, 11, 28, 43, 58, 74, 89, 105, 120, 135, 150, 165, 180, 196, 211, 226, 241, 6, 16, 33, 46, 60, 75, 92, 107, 123, 137, 156, 169, 185, 199, 214, 225, 11, 19, 30, 44, 57, 74, 89, 105, 121, 135, 152, 169, 186, 202, 218, 234, 12, 19, 29, 46, 57, 71, 88, 100, 120, 132, 148, 165, 182, 199, 216, 233, 17, 23, 35, 46, 56, 77, 92, 106, 123, 134, 152, 167, 185, 204, 222, 237, 14, 17, 45, 53, 63, 75, 89, 107, 115, 132, 151, 171, 188, 206, 221, 240, 9, 16, 29, 40, 56, 71, 88, 103, 119, 137, 154, 171, 189, 205, 222, 237, 16, 19, 36, 48, 57, 76, 87, 105, 118, 132, 150, 167, 185, 202, 218, 236, 12, 17, 29, 54, 71, 81, 94, 104, 126, 136, 149, 164, 182, 201, 221, 237, 15, 28, 47, 62, 79, 97, 115, 129, 142, 155, 168, 180, 194, 208, 223, 238, 8, 14, 30, 45, 62, 78, 94, 111, 127, 143, 159, 175, 192, 207, 223, 239, 17, 30, 49, 62, 79, 92, 107, 119, 132, 145, 160, 174, 190, 204, 220, 235, 14, 19, 36, 45, 61, 76, 91, 108, 121, 138, 154, 172, 189, 205, 222, 238, 12, 18, 31, 45, 60, 76, 91, 107, 123, 138, 154, 171, 187, 204, 221, 236, 13, 17, 31, 43, 53, 70, 83, 103, 114, 131, 149, 167, 185, 203, 220, 237, 17, 22, 35, 42, 58, 78, 93, 110, 125, 139, 155, 170, 188, 206, 224, 240, 8, 15, 34, 50, 67, 83, 99, 115, 131, 146, 162, 178, 193, 209, 224, 239, 13, 16, 41, 66, 73, 86, 95, 111, 128, 137, 150, 163, 183, 206, 225, 241, 17, 25, 37, 52, 63, 75, 92, 102, 119, 132, 144, 160, 175, 191, 212, 231, 19, 31, 49, 65, 83, 100, 117, 133, 147, 161, 174, 187, 200, 213, 227, 242, 18, 31, 52, 68, 88, 103, 117, 126, 138, 149, 163, 177, 192, 207, 223, 239, 16, 29, 47, 61, 76, 90, 106, 119, 133, 147, 161, 176, 193, 209, 224, 240, 15, 21, 35, 50, 61, 73, 86, 97, 110, 119, 129, 141, 175, 198, 218, 237 }; internal static readonly byte[] silk_NLSF_CB1_iCDF_WB = new byte[64] { 225, 204, 201, 184, 183, 175, 158, 154, 153, 135, 119, 115, 113, 110, 109, 99, 98, 95, 79, 68, 52, 50, 48, 45, 43, 32, 31, 27, 18, 10, 3, 0, 255, 251, 235, 230, 212, 201, 196, 182, 167, 166, 163, 151, 138, 124, 110, 104, 90, 78, 76, 70, 69, 57, 45, 34, 24, 21, 11, 6, 5, 4, 3, 0 }; internal static readonly byte[] silk_NLSF_CB2_SELECT_WB = new byte[256] { 0, 0, 0, 0, 0, 0, 0, 1, 100, 102, 102, 68, 68, 36, 34, 96, 164, 107, 158, 185, 180, 185, 139, 102, 64, 66, 36, 34, 34, 0, 1, 32, 208, 139, 141, 191, 152, 185, 155, 104, 96, 171, 104, 166, 102, 102, 102, 132, 1, 0, 0, 0, 0, 16, 16, 0, 80, 109, 78, 107, 185, 139, 103, 101, 208, 212, 141, 139, 173, 153, 123, 103, 36, 0, 0, 0, 0, 0, 0, 1, 48, 0, 0, 0, 0, 0, 0, 32, 68, 135, 123, 119, 119, 103, 69, 98, 68, 103, 120, 118, 118, 102, 71, 98, 134, 136, 157, 184, 182, 153, 139, 134, 208, 168, 248, 75, 189, 143, 121, 107, 32, 49, 34, 34, 34, 0, 17, 2, 210, 235, 139, 123, 185, 137, 105, 134, 98, 135, 104, 182, 100, 183, 171, 134, 100, 70, 68, 70, 66, 66, 34, 131, 64, 166, 102, 68, 36, 2, 1, 0, 134, 166, 102, 68, 34, 34, 66, 132, 212, 246, 158, 139, 107, 107, 87, 102, 100, 219, 125, 122, 137, 118, 103, 132, 114, 135, 137, 105, 171, 106, 50, 34, 164, 214, 141, 143, 185, 151, 121, 103, 192, 34, 0, 0, 0, 0, 0, 1, 208, 109, 74, 187, 134, 249, 159, 137, 102, 110, 154, 118, 87, 101, 119, 101, 0, 2, 0, 36, 36, 66, 68, 35, 96, 164, 102, 100, 36, 0, 2, 33, 167, 138, 174, 102, 100, 84, 2, 2, 100, 107, 120, 119, 36, 197, 24, 0 }; internal static readonly byte[] silk_NLSF_CB2_iCDF_WB = new byte[72] { 255, 254, 253, 244, 12, 3, 2, 1, 0, 255, 254, 252, 224, 38, 3, 2, 1, 0, 255, 254, 251, 209, 57, 4, 2, 1, 0, 255, 254, 244, 195, 69, 4, 2, 1, 0, 255, 251, 232, 184, 84, 7, 2, 1, 0, 255, 254, 240, 186, 86, 14, 2, 1, 0, 255, 254, 239, 178, 91, 30, 5, 1, 0, 255, 248, 227, 177, 100, 19, 2, 1, 0 }; internal static readonly byte[] silk_NLSF_CB2_BITS_WB_Q5 = new byte[72] { 255, 255, 255, 156, 4, 154, 255, 255, 255, 255, 255, 227, 102, 15, 92, 255, 255, 255, 255, 255, 213, 83, 24, 72, 236, 255, 255, 255, 255, 150, 76, 33, 63, 214, 255, 255, 255, 190, 121, 77, 43, 55, 185, 255, 255, 255, 245, 137, 71, 43, 59, 139, 255, 255, 255, 255, 131, 66, 50, 66, 107, 194, 255, 255, 166, 116, 76, 55, 53, 125, 255, 255 }; internal static readonly byte[] silk_NLSF_PRED_WB_Q8 = new byte[30] { 175, 148, 160, 176, 178, 173, 174, 164, 177, 174, 196, 182, 198, 192, 182, 68, 62, 66, 60, 72, 117, 85, 90, 118, 136, 151, 142, 160, 142, 155 }; internal static readonly short[] silk_NLSF_DELTA_MIN_WB_Q15 = new short[17] { 100, 3, 40, 3, 3, 3, 5, 14, 14, 10, 11, 3, 8, 9, 7, 3, 347 }; internal static readonly NLSFCodebook silk_NLSF_CB_WB = new NLSFCodebook { nVectors = 32, order = 16, quantStepSize_Q16 = 9830, invQuantStepSize_Q6 = 427, CB1_NLSF_Q8 = silk_NLSF_CB1_WB_Q8, CB1_iCDF = silk_NLSF_CB1_iCDF_WB, pred_Q8 = silk_NLSF_PRED_WB_Q8, ec_sel = silk_NLSF_CB2_SELECT_WB, ec_iCDF = silk_NLSF_CB2_iCDF_WB, ec_Rates_Q5 = silk_NLSF_CB2_BITS_WB_Q5, deltaMin_Q15 = silk_NLSF_DELTA_MIN_WB_Q15 }; internal static readonly int[] silk_TargetRate_table_NB = new int[8] { 0, 8000, 9400, 11500, 13500, 17500, 25000, 80000 }; internal static readonly int[] silk_TargetRate_table_MB = new int[8] { 0, 9000, 12000, 14500, 18500, 24500, 35500, 80000 }; internal static readonly int[] silk_TargetRate_table_WB = new int[8] { 0, 10500, 14000, 17000, 21500, 28500, 42000, 80000 }; internal static readonly short[] silk_SNR_table_Q1 = new short[8] { 18, 29, 38, 40, 46, 52, 62, 84 }; internal static readonly short[] silk_stereo_pred_quant_Q13 = new short[16] { -13732, -10050, -8266, -7526, -6500, -5000, -2950, -820, 820, 2950, 5000, 6500, 7526, 8266, 10050, 13732 }; internal static readonly byte[] silk_stereo_pred_joint_iCDF = new byte[25] { 249, 247, 246, 245, 244, 234, 210, 202, 201, 200, 197, 174, 82, 59, 56, 55, 54, 46, 22, 12, 11, 10, 9, 7, 0 }; internal static readonly byte[] silk_stereo_only_code_mid_iCDF = new byte[2] { 64, 0 }; internal static readonly byte[] silk_LBRR_flags_2_iCDF = new byte[3] { 203, 150, 0 }; internal static readonly byte[] silk_LBRR_flags_3_iCDF = new byte[7] { 215, 195, 166, 125, 110, 82, 0 }; internal static readonly byte[][] silk_LBRR_flags_iCDF_ptr = new byte[2][] { silk_LBRR_flags_2_iCDF, silk_LBRR_flags_3_iCDF }; internal static readonly byte[] silk_lsb_iCDF = new byte[2] { 120, 0 }; internal static readonly byte[] silk_LTPscale_iCDF = new byte[3] { 128, 64, 0 }; internal static readonly byte[] silk_type_offset_VAD_iCDF = new byte[4] { 232, 158, 10, 0 }; internal static readonly byte[] silk_type_offset_no_VAD_iCDF = new byte[2] { 230, 0 }; internal static readonly byte[] silk_NLSF_interpolation_factor_iCDF = new byte[5] { 243, 221, 192, 181, 0 }; internal static readonly short[][] silk_Quantization_Offsets_Q10 = new short[2][] { new short[2] { 100, 240 }, new short[2] { 32, 100 } }; internal static readonly short[] silk_LTPScales_table_Q14 = new short[3] { 15565, 12288, 8192 }; internal static readonly byte[] silk_uniform3_iCDF = new byte[3] { 171, 85, 0 }; internal static readonly byte[] silk_uniform4_iCDF = new byte[4] { 192, 128, 64, 0 }; internal static readonly byte[] silk_uniform5_iCDF = new byte[5] { 205, 154, 102, 51, 0 }; internal static readonly byte[] silk_uniform6_iCDF = new byte[6] { 213, 171, 128, 85, 43, 0 }; internal static readonly byte[] silk_uniform8_iCDF = new byte[8] { 224, 192, 160, 128, 96, 64, 32, 0 }; internal static readonly byte[] silk_NLSF_EXT_iCDF = new byte[7] { 100, 40, 16, 7, 3, 1, 0 }; internal static readonly int[][] silk_Transition_LP_B_Q28 = new int[5][] { new int[3] { 250767114, 501534038, 250767114 }, new int[3] { 209867381, 419732057, 209867381 }, new int[3] { 170987846, 341967853, 170987846 }, new int[3] { 131531482, 263046905, 131531482 }, new int[3] { 89306658, 178584282, 89306658 } }; internal static readonly int[][] silk_Transition_LP_A_Q28 = new int[5][] { new int[2] { 506393414, 239854379 }, new int[2] { 411067935, 169683996 }, new int[2] { 306733530, 116694253 }, new int[2] { 185807084, 77959395 }, new int[2] { 35497197, 57401098 } }; internal static readonly byte[] silk_pitch_lag_iCDF = new byte[32] { 253, 250, 244, 233, 212, 182, 150, 131, 120, 110, 98, 85, 72, 60, 49, 40, 32, 25, 19, 15, 13, 11, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; internal static readonly byte[] silk_pitch_delta_iCDF = new byte[21] { 210, 208, 206, 203, 199, 193, 183, 168, 142, 104, 74, 52, 37, 27, 20, 14, 10, 6, 4, 2, 0 }; internal static readonly byte[] silk_pitch_contour_iCDF = new byte[34] { 223, 201, 183, 167, 152, 138, 124, 111, 98, 88, 79, 70, 62, 56, 50, 44, 39, 35, 31, 27, 24, 21, 18, 16, 14, 12, 10, 8, 6, 4, 3, 2, 1, 0 }; internal static readonly byte[] silk_pitch_contour_NB_iCDF = new byte[11] { 188, 176, 155, 138, 119, 97, 67, 43, 26, 10, 0 }; internal static readonly byte[] silk_pitch_contour_10_ms_iCDF = new byte[12] { 165, 119, 80, 61, 47, 35, 27, 20, 14, 9, 4, 0 }; internal static readonly byte[] silk_pitch_contour_10_ms_NB_iCDF = new byte[3] { 113, 63, 0 }; internal static readonly byte[] silk_max_pulses_table = new byte[4] { 8, 10, 12, 16 }; internal static readonly byte[][] silk_pulses_per_block_iCDF = new byte[10][] { new byte[18] { 125, 51, 26, 18, 15, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, new byte[18] { 198, 105, 45, 22, 15, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, new byte[18] { 213, 162, 116, 83, 59, 43, 32, 24, 18, 15, 12, 9, 7, 6, 5, 3, 2, 0 }, new byte[18] { 239, 187, 116, 59, 28, 16, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, new byte[18] { 250, 229, 188, 135, 86, 51, 30, 19, 13, 10, 8, 6, 5, 4, 3, 2, 1, 0 }, new byte[18] { 249, 235, 213, 185, 156, 128, 103, 83, 66, 53, 42, 33, 26, 21, 17, 13, 10, 0 }, new byte[18] { 254, 249, 235, 206, 164, 118, 77, 46, 27, 16, 10, 7, 5, 4, 3, 2, 1, 0 }, new byte[18] { 255, 253, 249, 239, 220, 191, 156, 119, 85, 57, 37, 23, 15, 10, 6, 4, 2, 0 }, new byte[18] { 255, 253, 251, 246, 237, 223, 203, 179, 152, 124, 98, 75, 55, 40, 29, 21, 15, 0 }, new byte[18] { 255, 254, 253, 247, 220, 162, 106, 67, 42, 28, 18, 12, 9, 6, 4, 3, 2, 0 } }; internal static readonly byte[][] silk_pulses_per_block_BITS_Q5 = new byte[9][] { new byte[18] { 31, 57, 107, 160, 205, 205, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, new byte[18] { 69, 47, 67, 111, 166, 205, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, new byte[18] { 82, 74, 79, 95, 109, 128, 145, 160, 173, 205, 205, 205, 224, 255, 255, 224, 255, 224 }, new byte[18] { 125, 74, 59, 69, 97, 141, 182, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }, new byte[18] { 173, 115, 85, 73, 76, 92, 115, 145, 173, 205, 224, 224, 255, 255, 255, 255, 255, 255 }, new byte[18] { 166, 134, 113, 102, 101, 102, 107, 118, 125, 138, 145, 155, 166, 182, 192, 192, 205, 150 }, new byte[18] { 224, 182, 134, 101, 83, 79, 85, 97, 120, 145, 173, 205, 224, 255, 255, 255, 255, 255 }, new byte[18] { 255, 224, 192, 150, 120, 101, 92, 89, 93, 102, 118, 134, 160, 182, 192, 224, 224, 224 }, new byte[18] { 255, 224, 224, 182, 155, 134, 118, 109, 104, 102, 106, 111, 118, 131, 145, 160, 173, 131 } }; internal static readonly byte[][] silk_rate_levels_iCDF = new byte[2][] { new byte[9] { 241, 190, 178, 132, 87, 74, 41, 14, 0 }, new byte[9] { 223, 193, 157, 140, 106, 57, 39, 18, 0 } }; internal static readonly byte[][] silk_rate_levels_BITS_Q5 = new byte[2][] { new byte[9] { 131, 74, 141, 79, 80, 138, 95, 104, 134 }, new byte[9] { 95, 99, 91, 125, 93, 76, 123, 115, 123 } }; internal static readonly byte[] silk_shell_code_table0 = new byte[152] { 128, 0, 214, 42, 0, 235, 128, 21, 0, 244, 184, 72, 11, 0, 248, 214, 128, 42, 7, 0, 248, 225, 170, 80, 25, 5, 0, 251, 236, 198, 126, 54, 18, 3, 0, 250, 238, 211, 159, 82, 35, 15, 5, 0, 250, 231, 203, 168, 128, 88, 53, 25, 6, 0, 252, 238, 216, 185, 148, 108, 71, 40, 18, 4, 0, 253, 243, 225, 199, 166, 128, 90, 57, 31, 13, 3, 0, 254, 246, 233, 212, 183, 147, 109, 73, 44, 23, 10, 2, 0, 255, 250, 240, 223, 198, 166, 128, 90, 58, 33, 16, 6, 1, 0, 255, 251, 244, 231, 210, 181, 146, 110, 75, 46, 25, 12, 5, 1, 0, 255, 253, 248, 238, 221, 196, 164, 128, 92, 60, 35, 18, 8, 3, 1, 0, 255, 253, 249, 242, 229, 208, 180, 146, 110, 76, 48, 27, 14, 7, 3, 1, 0 }; internal static readonly byte[] silk_shell_code_table1 = new byte[152] { 129, 0, 207, 50, 0, 236, 129, 20, 0, 245, 185, 72, 10, 0, 249, 213, 129, 42, 6, 0, 250, 226, 169, 87, 27, 4, 0, 251, 233, 194, 130, 62, 20, 4, 0, 250, 236, 207, 160, 99, 47, 17, 3, 0, 255, 240, 217, 182, 131, 81, 41, 11, 1, 0, 255, 254, 233, 201, 159, 107, 61, 20, 2, 1, 0, 255, 249, 233, 206, 170, 128, 86, 50, 23, 7, 1, 0, 255, 250, 238, 217, 186, 148, 108, 70, 39, 18, 6, 1, 0, 255, 252, 243, 226, 200, 166, 128, 90, 56, 30, 13, 4, 1, 0, 255, 252, 245, 231, 209, 180, 146, 110, 76, 47, 25, 11, 4, 1, 0, 255, 253, 248, 237, 219, 194, 163, 128, 93, 62, 37, 19, 8, 3, 1, 0, 255, 254, 250, 241, 226, 205, 177, 145, 111, 79, 51, 30, 15, 6, 2, 1, 0 }; internal static readonly byte[] silk_shell_code_table2 = new byte[152] { 129, 0, 203, 54, 0, 234, 129, 23, 0, 245, 184, 73, 10, 0, 250, 215, 129, 41, 5, 0, 252, 232, 173, 86, 24, 3, 0, 253, 240, 200, 129, 56, 15, 2, 0, 253, 244, 217, 164, 94, 38, 10, 1, 0, 253, 245, 226, 189, 132, 71, 27, 7, 1, 0, 253, 246, 231, 203, 159, 105, 56, 23, 6, 1, 0, 255, 248, 235, 213, 179, 133, 85, 47, 19, 5, 1, 0, 255, 254, 243, 221, 194, 159, 117, 70, 37, 12, 2, 1, 0, 255, 254, 248, 234, 208, 171, 128, 85, 48, 22, 8, 2, 1, 0, 255, 254, 250, 240, 220, 189, 149, 107, 67, 36, 16, 6, 2, 1, 0, 255, 254, 251, 243, 227, 201, 166, 128, 90, 55, 29, 13, 5, 2, 1, 0, 255, 254, 252, 246, 234, 213, 183, 147, 109, 73, 43, 22, 10, 4, 2, 1, 0 }; internal static readonly byte[] silk_shell_code_table3 = new byte[152] { 130, 0, 200, 58, 0, 231, 130, 26, 0, 244, 184, 76, 12, 0, 249, 214, 130, 43, 6, 0, 252, 232, 173, 87, 24, 3, 0, 253, 241, 203, 131, 56, 14, 2, 0, 254, 246, 221, 167, 94, 35, 8, 1, 0, 254, 249, 232, 193, 130, 65, 23, 5, 1, 0, 255, 251, 239, 211, 162, 99, 45, 15, 4, 1, 0, 255, 251, 243, 223, 186, 131, 74, 33, 11, 3, 1, 0, 255, 252, 245, 230, 202, 158, 105, 57, 24, 8, 2, 1, 0, 255, 253, 247, 235, 214, 179, 132, 84, 44, 19, 7, 2, 1, 0, 255, 254, 250, 240, 223, 196, 159, 112, 69, 36, 15, 6, 2, 1, 0, 255, 254, 253, 245, 231, 209, 176, 136, 93, 55, 27, 11, 3, 2, 1, 0, 255, 254, 253, 252, 239, 221, 194, 158, 117, 76, 42, 18, 4, 3, 2, 1, 0 }; internal static readonly byte[] silk_shell_code_table_offsets = new byte[17] { 0, 0, 2, 5, 9, 14, 20, 27, 35, 44, 54, 65, 77, 90, 104, 119, 135 }; internal static readonly byte[] silk_sign_iCDF = new byte[42] { 254, 49, 67, 77, 82, 93, 99, 198, 11, 18, 24, 31, 36, 45, 255, 46, 66, 78, 87, 94, 104, 208, 14, 21, 32, 42, 51, 66, 255, 94, 104, 109, 112, 115, 118, 248, 53, 69, 80, 88, 95, 102 }; internal static readonly sbyte[,] delay_matrix_enc = new sbyte[5, 3] { { 6, 0, 3 }, { 0, 7, 3 }, { 0, 1, 10 }, { 0, 2, 6 }, { 18, 10, 12 } }; internal static readonly sbyte[,] delay_matrix_dec = new sbyte[3, 5] { { 4, 0, 2, 0, 0 }, { 0, 9, 4, 7, 4 }, { 0, 3, 12, 7, 7 } }; internal static readonly short[] silk_Resampler_3_4_COEFS = new short[29] { -20694, -13867, -49, 64, 17, -157, 353, -496, 163, 11047, 22205, -39, 6, 91, -170, 186, 23, -896, 6336, 19928, -19, -36, 102, -89, -24, 328, -951, 2568, 15909 }; internal static readonly short[] silk_Resampler_2_3_COEFS = new short[20] { -14457, -14019, 64, 128, -122, 36, 310, -768, 584, 9267, 17733, 12, 128, 18, -142, 288, -117, -865, 4123, 14459 }; internal static readonly short[] silk_Resampler_1_2_COEFS = new short[14] { 616, -14323, -10, 39, 58, -46, -84, 120, 184, -315, -541, 1284, 5380, 9024 }; internal static readonly short[] silk_Resampler_1_3_COEFS = new short[20] { 16102, -15162, -13, 0, 20, 26, 5, -31, -43, -4, 65, 90, 7, -157, -248, -44, 593, 1583, 2612, 3271 }; internal static readonly short[] silk_Resampler_1_4_COEFS = new short[20] { 22500, -15099, 3, -14, -20, -15, 2, 25, 37, 25, -16, -71, -107, -79, 50, 292, 623, 982, 1288, 1464 }; internal static readonly short[] silk_Resampler_1_6_COEFS = new short[20] { 27540, -15257, 17, 12, 8, 1, -10, -22, -30, -32, -22, 3, 44, 100, 168, 243, 317, 381, 429, 455 }; internal static readonly short[] silk_Resampler_2_3_COEFS_LQ = new short[6] { -2797, -6507, 4697, 10739, 1567, 8276 }; internal static readonly short[,] silk_resampler_frac_FIR_12 = new short[12, 4] { { 189, -600, 617, 30567 }, { 117, -159, -1070, 29704 }, { 52, 221, -2392, 28276 }, { -4, 529, -3350, 26341 }, { -48, 758, -3956, 23973 }, { -80, 905, -4235, 21254 }, { -99, 972, -4222, 18278 }, { -107, 967, -3957, 15143 }, { -103, 896, -3487, 11950 }, { -91, 773, -2865, 8798 }, { -71, 611, -2143, 5784 }, { -46, 425, -1375, 2996 } }; internal const short silk_resampler_down2_0 = 9872; internal const short silk_resampler_down2_1 = -25727; internal static readonly short[] silk_resampler_up2_hq_0 = new short[3] { 1746, 14986, -26453 }; internal static readonly short[] silk_resampler_up2_hq_1 = new short[3] { 6854, 25769, -9994 }; internal static readonly sbyte[][] silk_CB_lags_stage2_10_ms = new sbyte[2][] { new sbyte[3] { 0, 1, 0 }, new sbyte[3] { 0, 0, 1 } }; internal static readonly sbyte[][] silk_CB_lags_stage3_10_ms = new sbyte[2][] { new sbyte[12] { 0, 0, 1, -1, 1, -1, 2, -2, 2, -2, 3, -3 }, new sbyte[12] { 0, 1, 0, 1, -1, 2, -1, 2, -2, 3, -2, 3 } }; internal static readonly sbyte[][] silk_CB_lags_stage2 = new sbyte[4][] { new sbyte[11] { 0, 2, -1, -1, -1, 0, 0, 1, 1, 0, 1 }, new sbyte[11] { 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, new sbyte[11] { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 }, new sbyte[11] { 0, -1, 2, 1, 0, 1, 1, 0, 0, -1, -1 } }; internal static readonly sbyte[][] silk_CB_lags_stage3 = new sbyte[4][] { new sbyte[34] { 0, 0, 1, -1, 0, 1, -1, 0, -1, 1, -2, 2, -2, -2, 2, -3, 2, 3, -3, -4, 3, -4, 4, 4, -5, 5, -6, -5, 6, -7, 6, 5, 8, -9 }, new sbyte[34] { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 1, -1, 0, 1, -1, -1, 1, -1, 2, 1, -1, 2, -2, -2, 2, -2, 2, 2, 3, -3 }, new sbyte[34] { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, -1, 1, 0, 0, 2, 1, -1, 2, -1, -1, 2, -1, 2, 2, -1, 3, -2, -2, -2, 3 }, new sbyte[34] { 0, 1, 0, 0, 1, 0, 1, -1, 2, -1, 2, -1, 2, 3, -2, 3, -2, -2, 4, 4, -3, 5, -3, -4, 6, -4, 6, 5, -5, 8, -6, -5, -7, 9 } }; internal static readonly sbyte[][] silk_Lag_range_stage3_10_ms = new sbyte[2][] { new sbyte[2] { -3, 7 }, new sbyte[2] { -2, 7 } }; internal static readonly sbyte[][][] silk_Lag_range_stage3 = new sbyte[3][][] { new sbyte[4][] { new sbyte[2] { -5, 8 }, new sbyte[2] { -1, 6 }, new sbyte[2] { -1, 6 }, new sbyte[2] { -4, 10 } }, new sbyte[4][] { new sbyte[2] { -6, 10 }, new sbyte[2] { -2, 6 }, new sbyte[2] { -1, 6 }, new sbyte[2] { -5, 10 } }, new sbyte[4][] { new sbyte[2] { -9, 12 }, new sbyte[2] { -3, 7 }, new sbyte[2] { -2, 7 }, new sbyte[2] { -7, 13 } } }; internal static readonly sbyte[] silk_nb_cbk_searchs_stage3 = new sbyte[3] { 16, 24, 34 }; } internal class TuningParameters { internal const int BITRESERVOIR_DECAY_TIME_MS = 500; internal const float FIND_PITCH_WHITE_NOISE_FRACTION = 0.001f; internal const float FIND_PITCH_BANDWIDTH_EXPANSION = 0.99f; internal const float FIND_LPC_COND_FAC = 1E-05f; internal const float FIND_LTP_COND_FAC = 1E-05f; internal const float LTP_DAMPING = 0.05f; internal const float LTP_SMOOTHING = 0.1f; internal const float MU_LTP_QUANT_NB = 0.03f; internal const float MU_LTP_QUANT_MB = 0.025f; internal const float MU_LTP_QUANT_WB = 0.02f; internal const float MAX_SUM_LOG_GAIN_DB = 250f; internal const float VARIABLE_HP_SMTH_COEF1 = 0.1f; internal const float VARIABLE_HP_SMTH_COEF2 = 0.015f; internal const float VARIABLE_HP_MAX_DELTA_FREQ = 0.4f; internal const int VARIABLE_HP_MIN_CUTOFF_HZ = 60; internal const int VARIABLE_HP_MAX_CUTOFF_HZ = 100; internal const float SPEECH_ACTIVITY_DTX_THRES = 0.05f; internal const float LBRR_SPEECH_ACTIVITY_THRES = 0.3f; internal const float BG_SNR_DECR_dB = 2f; internal const float HARM_SNR_INCR_dB = 2f; internal const float SPARSE_SNR_INCR_dB = 2f; internal const float SPARSENESS_THRESHOLD_QNT_OFFSET = 0.75f; internal const float WARPING_MULTIPLIER = 0.015f; internal const float SHAPE_WHITE_NOISE_FRACTION = 5E-05f; internal const float BANDWIDTH_EXPANSION = 0.95f; internal const float LOW_RATE_BANDWIDTH_EXPANSION_DELTA = 0.01f; internal const float LOW_RATE_HARMONIC_BOOST = 0.1f; internal const float LOW_INPUT_QUALITY_HARMONIC_BOOST = 0.1f; internal const float HARMONIC_SHAPING = 0.3f; internal const float HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING = 0.2f; internal const float HP_NOISE_COEF = 0.25f; internal const float HARM_HP_NOISE_COEF = 0.35f; internal const float INPUT_TILT = 0.05f; internal const float HIGH_RATE_INPUT_TILT = 0.1f; internal const float LOW_FREQ_SHAPING = 4f; internal const float LOW_QUALITY_LOW_FREQ_SHAPING_DECR = 0.5f; internal const float SUBFR_SMTH_COEF = 0.4f; internal const float LAMBDA_OFFSET = 1.2f; internal const float LAMBDA_SPEECH_ACT = -0.2f; internal const float LAMBDA_DELAYED_DECISIONS = -0.05f; internal const float LAMBDA_INPUT_QUALITY = -0.1f; internal const float LAMBDA_CODING_QUALITY = -0.2f; internal const float LAMBDA_QUANT_OFFSET = 0.8f; internal const int REDUCE_BITRATE_10_MS_BPS = 2200; internal const int MAX_BANDWIDTH_SWITCH_DELAY_MS = 5000; } internal static class VoiceActivityDetection { private static readonly int[] tiltWeights = new int[4] { 30000, 6000, -12000, -12000 }; internal static int silk_VAD_Init(SilkVADState psSilk_VAD) { int result = 0; psSilk_VAD.Reset(); for (int i = 0; i < 4; i++) { psSilk_VAD.NoiseLevelBias[i] = Inlines.silk_max_32(Inlines.silk_DIV32_16(50, (short)(i + 1)), 1); } for (int i = 0; i < 4; i++) { psSilk_VAD.NL[i] = Inlines.silk_MUL(100, psSilk_VAD.NoiseLevelBias[i]); psSilk_VAD.inv_NL[i] = Inlines.silk_DIV32(int.MaxValue, psSilk_VAD.NL[i]); } psSilk_VAD.counter = 15; for (int i = 0; i < 4; i++) { psSilk_VAD.NrgRatioSmth_Q8[i] = 25600; } return result; } internal static int silk_VAD_GetSA_Q8(SilkChannelEncoder psEncC, Span pIn, int pIn_ptr) { int num = 0; int[] array = new int[4]; int[] array2 = new int[4]; int[] array3 = new int[4]; int result = 0; SilkVADState sVAD = psEncC.sVAD; int num2 = Inlines.silk_RSHIFT(psEncC.frame_length, 1); int num3 = Inlines.silk_RSHIFT(psEncC.frame_length, 2); int num4 = Inlines.silk_RSHIFT(psEncC.frame_length, 3); array3[0] = 0; array3[1] = num4 + num3; array3[2] = array3[1] + num4; array3[3] = array3[2] + num3; short[] array4 = new short[array3[3] + num2]; Filters.silk_ana_filt_bank_1(pIn, pIn_ptr, sVAD.AnaState, array4, array4, array3[3], psEncC.frame_length); Filters.silk_ana_filt_bank_1(array4, 0, sVAD.AnaState1, array4, array4, array3[2], num2); Filters.silk_ana_filt_bank_1(array4, 0, sVAD.AnaState2, array4, array4, array3[1], num3); array4[num4 - 1] = (short)Inlines.silk_RSHIFT(array4[num4 - 1], 1); short hPstate = array4[num4 - 1]; for (int num5 = num4 - 1; num5 > 0; num5--) { array4[num5 - 1] = (short)Inlines.silk_RSHIFT(array4[num5 - 1], 1); array4[num5] -= array4[num5 - 1]; } array4[0] -= sVAD.HPstate; sVAD.HPstate = hPstate; for (int i = 0; i < 4; i++) { num4 = Inlines.silk_RSHIFT(psEncC.frame_length, Inlines.silk_min_int(4 - i, 3)); int num6 = Inlines.silk_RSHIFT(num4, 2); int num7 = 0; array[i] = sVAD.XnrgSubfr[i]; for (int j = 0; j < 4; j++) { num = 0; for (int num5 = 0; num5 < num6; num5++) { int num8 = Inlines.silk_RSHIFT(array4[array3[i] + num5 + num7], 3); num = Inlines.silk_SMLABB(num, num8, num8); } if (j < 3) { array[i] = Inlines.silk_ADD_POS_SAT32(array[i], num); } else { array[i] = Inlines.silk_ADD_POS_SAT32(array[i], Inlines.silk_RSHIFT(num, 1)); } num7 += num6; } sVAD.XnrgSubfr[i] = num; } silk_VAD_GetNoiseLevels(array, sVAD); num = 0; int num9 = 0; int num10; for (int i = 0; i < 4; i++) { num10 = array[i] - sVAD.NL[i]; if (num10 > 0) { if ((array[i] & 0xFF800000u) == 0L) { array2[i] = Inlines.silk_DIV32(Inlines.silk_LSHIFT(array[i], 8), sVAD.NL[i] + 1); } else { array2[i] = Inlines.silk_DIV32(array[i], Inlines.silk_RSHIFT(sVAD.NL[i], 8) + 1); } int num11 = Inlines.silk_lin2log(array2[i]) - 1024; num = Inlines.silk_SMLABB(num, num11, num11); if (num10 < 1048576) { num11 = Inlines.silk_SMULWB(Inlines.silk_LSHIFT(Inlines.silk_SQRT_APPROX(num10), 6), num11); } num9 = Inlines.silk_SMLAWB(num9, tiltWeights[i], num11); } else { array2[i] = 256; } } num = Inlines.silk_DIV32_16(num, 4); int b = (short)(3 * Inlines.silk_SQRT_APPROX(num)); int num12 = Sigmoid.silk_sigm_Q15(Inlines.silk_SMULWB(45000, b) - 128); psEncC.input_tilt_Q15 = Inlines.silk_LSHIFT(Sigmoid.silk_sigm_Q15(num9) - 16384, 1); num10 = 0; for (int i = 0; i < 4; i++) { num10 += (i + 1) * Inlines.silk_RSHIFT(array[i] - sVAD.NL[i], 4); } if (num10 <= 0) { num12 = Inlines.silk_RSHIFT(num12, 1); } else if (num10 < 32768) { num10 = ((psEncC.frame_length != 10 * psEncC.fs_kHz) ? Inlines.silk_LSHIFT_SAT32(num10, 15) : Inlines.silk_LSHIFT_SAT32(num10, 16)); num10 = Inlines.silk_SQRT_APPROX(num10); num12 = Inlines.silk_SMULWB(32768 + num10, num12); } psEncC.speech_activity_Q8 = Inlines.silk_min_int(Inlines.silk_RSHIFT(num12, 7), 255); int num13 = Inlines.silk_SMULWB(4096, Inlines.silk_SMULWB(num12, num12)); if (psEncC.frame_length == 10 * psEncC.fs_kHz) { num13 >>= 1; } for (int i = 0; i < 4; i++) { sVAD.NrgRatioSmth_Q8[i] = Inlines.silk_SMLAWB(sVAD.NrgRatioSmth_Q8[i], array2[i] - sVAD.NrgRatioSmth_Q8[i], num13); int num11 = 3 * (Inlines.silk_lin2log(sVAD.NrgRatioSmth_Q8[i]) - 1024); psEncC.input_quality_bands_Q15[i] = Sigmoid.silk_sigm_Q15(Inlines.silk_RSHIFT(num11 - 2048, 4)); } return result; } internal static void silk_VAD_GetNoiseLevels(int[] pX, SilkVADState psSilk_VAD) { int b = ((psSilk_VAD.counter < 1000) ? Inlines.silk_DIV32_16(32767, (short)(Inlines.silk_RSHIFT(psSilk_VAD.counter, 4) + 1)) : 0); for (int i = 0; i < 4; i++) { int num = psSilk_VAD.NL[i]; int num2 = Inlines.silk_ADD_POS_SAT32(pX[i], psSilk_VAD.NoiseLevelBias[i]); int num3 = Inlines.silk_DIV32(int.MaxValue, num2); int a = ((num2 <= Inlines.silk_LSHIFT(num, 3)) ? ((num2 >= num) ? Inlines.silk_SMULWB(Inlines.silk_SMULWW(num3, num), 2048) : 1024) : 128); a = Inlines.silk_max_int(a, b); psSilk_VAD.inv_NL[i] = Inlines.silk_SMLAWB(psSilk_VAD.inv_NL[i], num3 - psSilk_VAD.inv_NL[i], a); num = Inlines.silk_DIV32(int.MaxValue, psSilk_VAD.inv_NL[i]); num = Inlines.silk_min(num, 16777215); psSilk_VAD.NL[i] = num; } psSilk_VAD.counter++; } } internal static class VQ_WMat_EC { internal static void silk_VQ_WMat_EC(BoxedValueSbyte ind, BoxedValueInt rate_dist_Q14, BoxedValueInt gain_Q7, short[] in_Q14, int in_Q14_ptr, int[] W_Q18, int W_Q18_ptr, sbyte[][] cb_Q7, byte[] cb_gain_Q7, byte[] cl_Q5, int mu_Q9, int max_gain_Q7, int L) { int num = 0; short[] array = new short[5]; rate_dist_Q14.Val = int.MaxValue; for (int i = 0; i < L; i++) { sbyte[] array2 = cb_Q7[num++]; int num2 = cb_gain_Q7[i]; array[0] = (short)(in_Q14[in_Q14_ptr] - Inlines.silk_LSHIFT(array2[0], 7)); array[1] = (short)(in_Q14[in_Q14_ptr + 1] - Inlines.silk_LSHIFT(array2[1], 7)); array[2] = (short)(in_Q14[in_Q14_ptr + 2] - Inlines.silk_LSHIFT(array2[2], 7)); array[3] = (short)(in_Q14[in_Q14_ptr + 3] - Inlines.silk_LSHIFT(array2[3], 7)); array[4] = (short)(in_Q14[in_Q14_ptr + 4] - Inlines.silk_LSHIFT(array2[4], 7)); int a = Inlines.silk_SMULBB(mu_Q9, cl_Q5[i]); a = Inlines.silk_ADD_LSHIFT32(a, Inlines.silk_max(Inlines.silk_SUB32(num2, max_gain_Q7), 0), 10); int a2 = Inlines.silk_SMULWB(W_Q18[W_Q18_ptr + 1], array[1]); a2 = Inlines.silk_SMLAWB(a2, W_Q18[W_Q18_ptr + 2], array[2]); a2 = Inlines.silk_SMLAWB(a2, W_Q18[W_Q18_ptr + 3], array[3]); a2 = Inlines.silk_SMLAWB(a2, W_Q18[W_Q18_ptr + 4], array[4]); a2 = Inlines.silk_LSHIFT(a2, 1); a2 = Inlines.silk_SMLAWB(a2, W_Q18[W_Q18_ptr], array[0]); a = Inlines.silk_SMLAWB(a, a2, array[0]); a2 = Inlines.silk_SMULWB(W_Q18[W_Q18_ptr + 7], array[2]); a2 = Inlines.silk_SMLAWB(a2, W_Q18[W_Q18_ptr + 8], array[3]); a2 = Inlines.silk_SMLAWB(a2, W_Q18[W_Q18_ptr + 9], array[4]); a2 = Inlines.silk_LSHIFT(a2, 1); a2 = Inlines.silk_SMLAWB(a2, W_Q18[W_Q18_ptr + 6], array[1]); a = Inlines.silk_SMLAWB(a, a2, array[1]); a2 = Inlines.silk_SMULWB(W_Q18[W_Q18_ptr + 13], array[3]); a2 = Inlines.silk_SMLAWB(a2, W_Q18[W_Q18_ptr + 14], array[4]); a2 = Inlines.silk_LSHIFT(a2, 1); a2 = Inlines.silk_SMLAWB(a2, W_Q18[W_Q18_ptr + 12], array[2]); a = Inlines.silk_SMLAWB(a, a2, array[2]); a2 = Inlines.silk_SMULWB(W_Q18[W_Q18_ptr + 19], array[4]); a2 = Inlines.silk_LSHIFT(a2, 1); a2 = Inlines.silk_SMLAWB(a2, W_Q18[W_Q18_ptr + 18], array[3]); a = Inlines.silk_SMLAWB(a, a2, array[3]); a2 = Inlines.silk_SMULWB(W_Q18[W_Q18_ptr + 24], array[4]); a = Inlines.silk_SMLAWB(a, a2, array[4]); if (a < rate_dist_Q14.Val) { rate_dist_Q14.Val = a; ind.Val = (sbyte)i; gain_Q7.Val = num2; } } } } } namespace Concentus.Silk.Structs { internal class CNGState { internal readonly int[] CNG_exc_buf_Q14 = new int[320]; internal readonly short[] CNG_smth_NLSF_Q15 = new short[16]; internal readonly int[] CNG_synth_state = new int[16]; internal int CNG_smth_Gain_Q16; internal int rand_seed; internal int fs_kHz; internal void Reset() { Arrays.MemSetInt(CNG_exc_buf_Q14, 0, 320); Arrays.MemSetShort(CNG_smth_NLSF_Q15, 0, 16); Arrays.MemSetInt(CNG_synth_state, 0, 16); CNG_smth_Gain_Q16 = 0; rand_seed = 0; fs_kHz = 0; } } internal class DecControlState { internal int nChannelsAPI; internal int nChannelsInternal; internal int API_sampleRate; internal int internalSampleRate; internal int payloadSize_ms; internal int prevPitchLag; internal void Reset() { nChannelsAPI = 0; nChannelsInternal = 0; API_sampleRate = 0; internalSampleRate = 0; payloadSize_ms = 0; prevPitchLag = 0; } } internal class EncControlState { internal int nChannelsAPI; internal int nChannelsInternal; internal int API_sampleRate; internal int maxInternalSampleRate; internal int minInternalSampleRate; internal int desiredInternalSampleRate; internal int payloadSize_ms; internal int bitRate; internal int packetLossPercentage; internal int complexity; internal int useInBandFEC; internal int useDTX; internal int useCBR; internal int maxBits; internal int toMono; internal int opusCanSwitch; internal int reducedDependency; internal int internalSampleRate; internal int allowBandwidthSwitch; internal int inWBmodeWithoutVariableLP; internal int stereoWidth_Q14; internal int switchReady; internal void Reset() { nChannelsAPI = 0; nChannelsInternal = 0; API_sampleRate = 0; maxInternalSampleRate = 0; minInternalSampleRate = 0; desiredInternalSampleRate = 0; payloadSize_ms = 0; bitRate = 0; packetLossPercentage = 0; complexity = 0; useInBandFEC = 0; useDTX = 0; useCBR = 0; maxBits = 0; toMono = 0; opusCanSwitch = 0; reducedDependency = 0; internalSampleRate = 0; allowBandwidthSwitch = 0; inWBmodeWithoutVariableLP = 0; stereoWidth_Q14 = 0; switchReady = 0; } internal int check_control_input() { if ((API_sampleRate != 8000 && API_sampleRate != 12000 && API_sampleRate != 16000 && API_sampleRate != 24000 && API_sampleRate != 32000 && API_sampleRate != 44100 && API_sampleRate != 48000) || (desiredInternalSampleRate != 8000 && desiredInternalSampleRate != 12000 && desiredInternalSampleRate != 16000) || (maxInternalSampleRate != 8000 && maxInternalSampleRate != 12000 && maxInternalSampleRate != 16000) || (minInternalSampleRate != 8000 && minInternalSampleRate != 12000 && minInternalSampleRate != 16000) || minInternalSampleRate > desiredInternalSampleRate || maxInternalSampleRate < desiredInternalSampleRate || minInternalSampleRate > maxInternalSampleRate) { return SilkError.SILK_ENC_FS_NOT_SUPPORTED; } if (payloadSize_ms != 10 && payloadSize_ms != 20 && payloadSize_ms != 40 && payloadSize_ms != 60) { return SilkError.SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; } if (packetLossPercentage < 0 || packetLossPercentage > 100) { return SilkError.SILK_ENC_INVALID_LOSS_RATE; } if (useDTX < 0 || useDTX > 1) { return SilkError.SILK_ENC_INVALID_DTX_SETTING; } if (useCBR < 0 || useCBR > 1) { return SilkError.SILK_ENC_INVALID_CBR_SETTING; } if (useInBandFEC < 0 || useInBandFEC > 1) { return SilkError.SILK_ENC_INVALID_INBAND_FEC_SETTING; } if (nChannelsAPI < 1 || nChannelsAPI > 2) { return SilkError.SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; } if (nChannelsInternal < 1 || nChannelsInternal > 2) { return SilkError.SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; } if (nChannelsInternal > nChannelsAPI) { return SilkError.SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; } if (complexity < 0 || complexity > 10) { return SilkError.SILK_ENC_INVALID_COMPLEXITY_SETTING; } return SilkError.SILK_NO_ERROR; } } internal class NLSFCodebook { internal short nVectors; internal short order; internal short quantStepSize_Q16; internal short invQuantStepSize_Q6; internal byte[] CB1_NLSF_Q8; internal byte[] CB1_iCDF; internal byte[] pred_Q8; internal byte[] ec_sel; internal byte[] ec_iCDF; internal byte[] ec_Rates_Q5; internal short[] deltaMin_Q15; internal void Reset() { nVectors = 0; order = 0; quantStepSize_Q16 = 0; invQuantStepSize_Q6 = 0; CB1_NLSF_Q8 = null; CB1_iCDF = null; pred_Q8 = null; ec_sel = null; ec_iCDF = null; ec_Rates_Q5 = null; deltaMin_Q15 = null; } } internal class PLCStruct { internal int pitchL_Q8; internal readonly short[] LTPCoef_Q14 = new short[5]; internal readonly short[] prevLPC_Q12 = new short[16]; internal int last_frame_lost; internal int rand_seed; internal short randScale_Q14; internal int conc_energy; internal int conc_energy_shift; internal short prevLTP_scale_Q14; internal readonly int[] prevGain_Q16 = new int[2]; internal int fs_kHz; internal int nb_subfr; internal int subfr_length; internal void Reset() { pitchL_Q8 = 0; Arrays.MemSetShort(LTPCoef_Q14, 0, 5); Arrays.MemSetShort(prevLPC_Q12, 0, 16); last_frame_lost = 0; rand_seed = 0; randScale_Q14 = 0; conc_energy = 0; conc_energy_shift = 0; prevLTP_scale_Q14 = 0; Arrays.MemSetInt(prevGain_Q16, 0, 2); fs_kHz = 0; nb_subfr = 0; subfr_length = 0; } } internal class SideInfoIndices { internal readonly sbyte[] GainsIndices = new sbyte[4]; internal readonly sbyte[] LTPIndex = new sbyte[4]; internal readonly sbyte[] NLSFIndices = new sbyte[17]; internal short lagIndex; internal sbyte contourIndex; internal sbyte signalType; internal sbyte quantOffsetType; internal sbyte NLSFInterpCoef_Q2; internal sbyte PERIndex; internal sbyte LTP_scaleIndex; internal sbyte Seed; internal void Reset() { Arrays.MemSetSbyte(GainsIndices, 0, 4); Arrays.MemSetSbyte(LTPIndex, 0, 4); Arrays.MemSetSbyte(NLSFIndices, 0, 17); lagIndex = 0; contourIndex = 0; signalType = 0; quantOffsetType = 0; NLSFInterpCoef_Q2 = 0; PERIndex = 0; LTP_scaleIndex = 0; Seed = 0; } internal void Assign(SideInfoIndices other) { Arrays.MemCopy(other.GainsIndices, 0, GainsIndices, 0, 4); Arrays.MemCopy(other.LTPIndex, 0, LTPIndex, 0, 4); Arrays.MemCopy(other.NLSFIndices, 0, NLSFIndices, 0, 17); lagIndex = other.lagIndex; contourIndex = other.contourIndex; signalType = other.signalType; quantOffsetType = other.quantOffsetType; NLSFInterpCoef_Q2 = other.NLSFInterpCoef_Q2; PERIndex = other.PERIndex; LTP_scaleIndex = other.LTP_scaleIndex; Seed = other.Seed; } } internal class SilkChannelDecoder { internal int prev_gain_Q16; internal readonly int[] exc_Q14 = new int[320]; internal readonly int[] sLPC_Q14_buf = new int[16]; internal readonly short[] outBuf = new short[480]; internal int lagPrev; internal sbyte LastGainIndex; internal int fs_kHz; internal int fs_API_hz; internal int nb_subfr; internal int frame_length; internal int subfr_length; internal int ltp_mem_length; internal int LPC_order; internal readonly short[] prevNLSF_Q15 = new short[16]; internal int first_frame_after_reset; internal byte[] pitch_lag_low_bits_iCDF; internal byte[] pitch_contour_iCDF; internal int nFramesDecoded; internal int nFramesPerPacket; internal int ec_prevSignalType; internal short ec_prevLagIndex; internal readonly int[] VAD_flags = new int[3]; internal int LBRR_flag; internal readonly int[] LBRR_flags = new int[3]; internal readonly SilkResamplerState resampler_state = new SilkResamplerState(); internal NLSFCodebook psNLSF_CB; internal readonly SideInfoIndices indices = new SideInfoIndices(); internal readonly CNGState sCNG = new CNGState(); internal int lossCnt; internal int prevSignalType; internal readonly PLCStruct sPLC = new PLCStruct(); internal void Reset() { prev_gain_Q16 = 0; Arrays.MemSetInt(exc_Q14, 0, 320); Arrays.MemSetInt(sLPC_Q14_buf, 0, 16); Arrays.MemSetShort(outBuf, 0, 480); lagPrev = 0; LastGainIndex = 0; fs_kHz = 0; fs_API_hz = 0; nb_subfr = 0; frame_length = 0; subfr_length = 0; ltp_mem_length = 0; LPC_order = 0; Arrays.MemSetShort(prevNLSF_Q15, 0, 16); first_frame_after_reset = 0; pitch_lag_low_bits_iCDF = null; pitch_contour_iCDF = null; nFramesDecoded = 0; nFramesPerPacket = 0; ec_prevSignalType = 0; ec_prevLagIndex = 0; Arrays.MemSetInt(VAD_flags, 0, 3); LBRR_flag = 0; Arrays.MemSetInt(LBRR_flags, 0, 3); resampler_state.Reset(); psNLSF_CB = null; indices.Reset(); sCNG.Reset(); lossCnt = 0; prevSignalType = 0; sPLC.Reset(); } internal int silk_init_decoder() { Reset(); first_frame_after_reset = 1; prev_gain_Q16 = 65536; silk_CNG_Reset(); silk_PLC_Reset(); return 0; } private void silk_CNG_Reset() { int num = Inlines.silk_DIV32_16(32767, LPC_order + 1); int num2 = 0; for (int i = 0; i < LPC_order; i++) { num2 += num; sCNG.CNG_smth_NLSF_Q15[i] = (short)num2; } sCNG.CNG_smth_Gain_Q16 = 0; sCNG.rand_seed = 3176576; } private void silk_PLC_Reset() { sPLC.pitchL_Q8 = Inlines.silk_LSHIFT(frame_length, 7); sPLC.prevGain_Q16[0] = 65536; sPLC.prevGain_Q16[1] = 65536; sPLC.subfr_length = 20; sPLC.nb_subfr = 2; } internal int silk_decoder_set_fs(int fs_kHz, int fs_API_Hz) { int num = 0; subfr_length = Inlines.silk_SMULBB(5, fs_kHz); int num2 = Inlines.silk_SMULBB(nb_subfr, subfr_length); if (this.fs_kHz != fs_kHz || fs_API_hz != fs_API_Hz) { num += Resampler.silk_resampler_init(resampler_state, Inlines.silk_SMULBB(fs_kHz, 1000), fs_API_Hz, 0); fs_API_hz = fs_API_Hz; } if (this.fs_kHz != fs_kHz || num2 != frame_length) { if (fs_kHz == 8) { if (nb_subfr == 4) { pitch_contour_iCDF = Tables.silk_pitch_contour_NB_iCDF; } else { pitch_contour_iCDF = Tables.silk_pitch_contour_10_ms_NB_iCDF; } } else if (nb_subfr == 4) { pitch_contour_iCDF = Tables.silk_pitch_contour_iCDF; } else { pitch_contour_iCDF = Tables.silk_pitch_contour_10_ms_iCDF; } if (this.fs_kHz != fs_kHz) { ltp_mem_length = Inlines.silk_SMULBB(20, fs_kHz); if (fs_kHz == 8 || fs_kHz == 12) { LPC_order = 10; psNLSF_CB = Tables.silk_NLSF_CB_NB_MB; } else { LPC_order = 16; psNLSF_CB = Tables.silk_NLSF_CB_WB; } switch (fs_kHz) { case 16: pitch_lag_low_bits_iCDF = Tables.silk_uniform8_iCDF; break; case 12: pitch_lag_low_bits_iCDF = Tables.silk_uniform6_iCDF; break; case 8: pitch_lag_low_bits_iCDF = Tables.silk_uniform4_iCDF; break; } first_frame_after_reset = 1; lagPrev = 100; LastGainIndex = 10; prevSignalType = 0; Arrays.MemSetShort(outBuf, 0, 480); Arrays.MemSetInt(sLPC_Q14_buf, 0, 16); } this.fs_kHz = fs_kHz; frame_length = num2; } return num; } internal int silk_decode_frame(EntropyCoder psRangeDec, ReadOnlySpan frameData, Span pOut, int pOut_ptr, BoxedValueInt pN, int lostFlag, int condCoding) { SilkDecoderControl silkDecoderControl = new SilkDecoderControl(); int num = frame_length; silkDecoderControl.LTP_scale_Q14 = 0; if (lostFlag == 0 || (lostFlag == 2 && LBRR_flags[nFramesDecoded] == 1)) { short[] pulses = new short[(num + 16 - 1) & -16]; DecodeIndices.silk_decode_indices(this, psRangeDec, frameData, nFramesDecoded, lostFlag, condCoding); DecodePulses.silk_decode_pulses(psRangeDec, frameData, pulses, indices.signalType, indices.quantOffsetType, frame_length); DecodeParameters.silk_decode_parameters(this, silkDecoderControl, condCoding); DecodeCore.silk_decode_core(this, silkDecoderControl, pOut, pOut_ptr, pulses); PLC.silk_PLC(this, silkDecoderControl, pOut, pOut_ptr, 0); lossCnt = 0; prevSignalType = indices.signalType; first_frame_after_reset = 0; } else { PLC.silk_PLC(this, silkDecoderControl, pOut, pOut_ptr, 1); } int num2 = ltp_mem_length - frame_length; Arrays.MemMoveShort(outBuf, frame_length, 0, num2); pOut.Slice(pOut_ptr, frame_length).CopyTo(outBuf.AsSpan(num2)); CNG.silk_CNG(this, silkDecoderControl, pOut, pOut_ptr, num); PLC.silk_PLC_glue_frames(this, pOut, pOut_ptr, num); lagPrev = silkDecoderControl.pitchL[nb_subfr - 1]; pN.Val = num; return 0; } } internal class SilkChannelEncoder { internal readonly int[] In_HP_State = new int[2]; internal int variable_HP_smth1_Q15; internal int variable_HP_smth2_Q15; internal readonly SilkLPState sLP = new SilkLPState(); internal readonly SilkVADState sVAD = new SilkVADState(); internal readonly SilkNSQState sNSQ = new SilkNSQState(); internal readonly short[] prev_NLSFq_Q15 = new short[16]; internal int speech_activity_Q8; internal int allow_bandwidth_switch; internal sbyte LBRRprevLastGainIndex; internal sbyte prevSignalType; internal int prevLag; internal int pitch_LPC_win_length; internal int max_pitch_lag; internal int API_fs_Hz; internal int prev_API_fs_Hz; internal int maxInternal_fs_Hz; internal int minInternal_fs_Hz; internal int desiredInternal_fs_Hz; internal int fs_kHz; internal int nb_subfr; internal int frame_length; internal int subfr_length; internal int ltp_mem_length; internal int la_pitch; internal int la_shape; internal int shapeWinLength; internal int TargetRate_bps; internal int PacketSize_ms; internal int PacketLoss_perc; internal int frameCounter; internal int Complexity; internal int nStatesDelayedDecision; internal int useInterpolatedNLSFs; internal int shapingLPCOrder; internal int predictLPCOrder; internal int pitchEstimationComplexity; internal int pitchEstimationLPCOrder; internal int pitchEstimationThreshold_Q16; internal int LTPQuantLowComplexity; internal int mu_LTP_Q9; internal int sum_log_gain_Q7; internal int NLSF_MSVQ_Survivors; internal int first_frame_after_reset; internal int controlled_since_last_payload; internal int warping_Q16; internal int useCBR; internal int prefillFlag; internal byte[] pitch_lag_low_bits_iCDF; internal byte[] pitch_contour_iCDF; internal NLSFCodebook psNLSF_CB; internal readonly int[] input_quality_bands_Q15 = new int[4]; internal int input_tilt_Q15; internal int SNR_dB_Q7; internal readonly sbyte[] VAD_flags = new sbyte[3]; internal sbyte LBRR_flag; internal readonly int[] LBRR_flags = new int[3]; internal readonly SideInfoIndices indices = new SideInfoIndices(); internal readonly sbyte[] pulses = new sbyte[320]; internal readonly short[] inputBuf = new short[322]; internal int inputBufIx; internal int nFramesPerPacket; internal int nFramesEncoded; internal int nChannelsAPI; internal int nChannelsInternal; internal int channelNb; internal int frames_since_onset; internal int ec_prevSignalType; internal short ec_prevLagIndex; internal readonly SilkResamplerState resampler_state = new SilkResamplerState(); internal int useDTX; internal int inDTX; internal int noSpeechCounter; internal int useInBandFEC; internal int LBRR_enabled; internal int LBRR_GainIncreases; internal readonly SideInfoIndices[] indices_LBRR = new SideInfoIndices[3]; internal readonly sbyte[][] pulses_LBRR = Arrays.InitTwoDimensionalArray(3, 320); internal readonly SilkShapeState sShape = new SilkShapeState(); internal readonly SilkPrefilterState sPrefilt = new SilkPrefilterState(); internal readonly short[] x_buf = new short[720]; internal int LTPCorr_Q15; internal SilkChannelEncoder() { for (int i = 0; i < 3; i++) { indices_LBRR[i] = new SideInfoIndices(); } } internal void Reset() { Arrays.MemSetInt(In_HP_State, 0, 2); variable_HP_smth1_Q15 = 0; variable_HP_smth2_Q15 = 0; sLP.Reset(); sVAD.Reset(); sNSQ.Reset(); Arrays.MemSetShort(prev_NLSFq_Q15, 0, 16); speech_activity_Q8 = 0; allow_bandwidth_switch = 0; LBRRprevLastGainIndex = 0; prevSignalType = 0; prevLag = 0; pitch_LPC_win_length = 0; max_pitch_lag = 0; API_fs_Hz = 0; prev_API_fs_Hz = 0; maxInternal_fs_Hz = 0; minInternal_fs_Hz = 0; desiredInternal_fs_Hz = 0; fs_kHz = 0; nb_subfr = 0; frame_length = 0; subfr_length = 0; ltp_mem_length = 0; la_pitch = 0; la_shape = 0; shapeWinLength = 0; TargetRate_bps = 0; PacketSize_ms = 0; PacketLoss_perc = 0; frameCounter = 0; Complexity = 0; nStatesDelayedDecision = 0; useInterpolatedNLSFs = 0; shapingLPCOrder = 0; predictLPCOrder = 0; pitchEstimationComplexity = 0; pitchEstimationLPCOrder = 0; pitchEstimationThreshold_Q16 = 0; LTPQuantLowComplexity = 0; mu_LTP_Q9 = 0; sum_log_gain_Q7 = 0; NLSF_MSVQ_Survivors = 0; first_frame_after_reset = 0; controlled_since_last_payload = 0; warping_Q16 = 0; useCBR = 0; prefillFlag = 0; pitch_lag_low_bits_iCDF = null; pitch_contour_iCDF = null; psNLSF_CB = null; Arrays.MemSetInt(input_quality_bands_Q15, 0, 4); input_tilt_Q15 = 0; SNR_dB_Q7 = 0; Arrays.MemSetSbyte(VAD_flags, 0, 3); LBRR_flag = 0; Arrays.MemSetInt(LBRR_flags, 0, 3); indices.Reset(); Arrays.MemSetSbyte(pulses, 0, 320); Arrays.MemSetShort(inputBuf, 0, 322); inputBufIx = 0; nFramesPerPacket = 0; nFramesEncoded = 0; nChannelsAPI = 0; nChannelsInternal = 0; channelNb = 0; frames_since_onset = 0; ec_prevSignalType = 0; ec_prevLagIndex = 0; resampler_state.Reset(); useDTX = 0; inDTX = 0; noSpeechCounter = 0; useInBandFEC = 0; LBRR_enabled = 0; LBRR_GainIncreases = 0; for (int i = 0; i < 3; i++) { indices_LBRR[i].Reset(); Arrays.MemSetSbyte(pulses_LBRR[i], 0, 320); } sShape.Reset(); sPrefilt.Reset(); Arrays.MemSetShort(x_buf, 0, 720); LTPCorr_Q15 = 0; } internal int silk_control_encoder(EncControlState encControl, int TargetRate_bps, int allow_bw_switch, int channelNb, int force_fs_kHz) { int result = SilkError.SILK_NO_ERROR; useDTX = encControl.useDTX; useCBR = encControl.useCBR; API_fs_Hz = encControl.API_sampleRate; maxInternal_fs_Hz = encControl.maxInternalSampleRate; minInternal_fs_Hz = encControl.minInternalSampleRate; desiredInternal_fs_Hz = encControl.desiredInternalSampleRate; useInBandFEC = encControl.useInBandFEC; nChannelsAPI = encControl.nChannelsAPI; nChannelsInternal = encControl.nChannelsInternal; allow_bandwidth_switch = allow_bw_switch; this.channelNb = channelNb; if (controlled_since_last_payload != 0 && prefillFlag == 0) { if (API_fs_Hz != prev_API_fs_Hz && fs_kHz > 0) { result = silk_setup_resamplers(fs_kHz); } return result; } int num = silk_control_audio_bandwidth(encControl); if (force_fs_kHz != 0) { num = force_fs_kHz; } result = silk_setup_resamplers(num); result = silk_setup_fs(num, encControl.payloadSize_ms); result = silk_setup_complexity(encControl.complexity); PacketLoss_perc = encControl.packetLossPercentage; result = silk_setup_LBRR(TargetRate_bps); controlled_since_last_payload = 1; return result; } private int silk_setup_resamplers(int fs_kHz) { int num = 0; if (this.fs_kHz != fs_kHz || prev_API_fs_Hz != API_fs_Hz) { if (this.fs_kHz == 0) { num += Resampler.silk_resampler_init(resampler_state, API_fs_Hz, fs_kHz * 1000, 1); } else { SilkResamplerState silkResamplerState = null; int num2 = Inlines.silk_LSHIFT(nb_subfr * 5, 1) + 5; int inLen = num2 * this.fs_kHz; silkResamplerState = new SilkResamplerState(); num += Resampler.silk_resampler_init(silkResamplerState, Inlines.silk_SMULBB(this.fs_kHz, 1000), API_fs_Hz, 0); int num3 = num2 * Inlines.silk_DIV32_16(API_fs_Hz, 1000); short[] array = new short[num3]; num += Resampler.silk_resampler(silkResamplerState, array, 0, x_buf, 0, inLen); num += Resampler.silk_resampler_init(resampler_state, API_fs_Hz, Inlines.silk_SMULBB(fs_kHz, 1000), 1); num += Resampler.silk_resampler(resampler_state, x_buf, 0, array, 0, num3); } } prev_API_fs_Hz = API_fs_Hz; return num; } private int silk_setup_fs(int fs_kHz, int PacketSize_ms) { int result = SilkError.SILK_NO_ERROR; if (PacketSize_ms != this.PacketSize_ms) { if (PacketSize_ms != 10 && PacketSize_ms != 20 && PacketSize_ms != 40 && PacketSize_ms != 60) { result = SilkError.SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; } if (PacketSize_ms <= 10) { nFramesPerPacket = 1; nb_subfr = ((PacketSize_ms != 10) ? 1 : 2); frame_length = Inlines.silk_SMULBB(PacketSize_ms, fs_kHz); pitch_LPC_win_length = Inlines.silk_SMULBB(14, fs_kHz); if (this.fs_kHz == 8) { pitch_contour_iCDF = Tables.silk_pitch_contour_10_ms_NB_iCDF; } else { pitch_contour_iCDF = Tables.silk_pitch_contour_10_ms_iCDF; } } else { nFramesPerPacket = Inlines.silk_DIV32_16(PacketSize_ms, 20); nb_subfr = 4; frame_length = Inlines.silk_SMULBB(20, fs_kHz); pitch_LPC_win_length = Inlines.silk_SMULBB(24, fs_kHz); if (this.fs_kHz == 8) { pitch_contour_iCDF = Tables.silk_pitch_contour_NB_iCDF; } else { pitch_contour_iCDF = Tables.silk_pitch_contour_iCDF; } } this.PacketSize_ms = PacketSize_ms; TargetRate_bps = 0; } if (this.fs_kHz != fs_kHz) { sShape.Reset(); sPrefilt.Reset(); sNSQ.Reset(); Arrays.MemSetShort(prev_NLSFq_Q15, 0, 16); Arrays.MemSetInt(sLP.In_LP_State, 0, 2); inputBufIx = 0; nFramesEncoded = 0; TargetRate_bps = 0; prevLag = 100; first_frame_after_reset = 1; sPrefilt.lagPrev = 100; sShape.LastGainIndex = 10; sNSQ.lagPrev = 100; sNSQ.prev_gain_Q16 = 65536; prevSignalType = 0; this.fs_kHz = fs_kHz; if (this.fs_kHz == 8) { if (nb_subfr == 4) { pitch_contour_iCDF = Tables.silk_pitch_contour_NB_iCDF; } else { pitch_contour_iCDF = Tables.silk_pitch_contour_10_ms_NB_iCDF; } } else if (nb_subfr == 4) { pitch_contour_iCDF = Tables.silk_pitch_contour_iCDF; } else { pitch_contour_iCDF = Tables.silk_pitch_contour_10_ms_iCDF; } if (this.fs_kHz == 8 || this.fs_kHz == 12) { predictLPCOrder = 10; psNLSF_CB = Tables.silk_NLSF_CB_NB_MB; } else { predictLPCOrder = 16; psNLSF_CB = Tables.silk_NLSF_CB_WB; } subfr_length = 5 * fs_kHz; frame_length = Inlines.silk_SMULBB(subfr_length, nb_subfr); ltp_mem_length = Inlines.silk_SMULBB(20, fs_kHz); la_pitch = Inlines.silk_SMULBB(2, fs_kHz); max_pitch_lag = Inlines.silk_SMULBB(18, fs_kHz); if (nb_subfr == 4) { pitch_LPC_win_length = Inlines.silk_SMULBB(24, fs_kHz); } else { pitch_LPC_win_length = Inlines.silk_SMULBB(14, fs_kHz); } if (this.fs_kHz == 16) { mu_LTP_Q9 = 10; pitch_lag_low_bits_iCDF = Tables.silk_uniform8_iCDF; } else if (this.fs_kHz == 12) { mu_LTP_Q9 = 13; pitch_lag_low_bits_iCDF = Tables.silk_uniform6_iCDF; } else { mu_LTP_Q9 = 15; pitch_lag_low_bits_iCDF = Tables.silk_uniform4_iCDF; } } return result; } private int silk_setup_complexity(int Complexity) { if (Complexity < 2) { pitchEstimationComplexity = 0; pitchEstimationThreshold_Q16 = 52429; pitchEstimationLPCOrder = 6; shapingLPCOrder = 8; la_shape = 3 * fs_kHz; nStatesDelayedDecision = 1; useInterpolatedNLSFs = 0; LTPQuantLowComplexity = 1; NLSF_MSVQ_Survivors = 2; warping_Q16 = 0; } else if (Complexity < 4) { pitchEstimationComplexity = 1; pitchEstimationThreshold_Q16 = 49807; pitchEstimationLPCOrder = 8; shapingLPCOrder = 10; la_shape = 5 * fs_kHz; nStatesDelayedDecision = 1; useInterpolatedNLSFs = 0; LTPQuantLowComplexity = 0; NLSF_MSVQ_Survivors = 4; warping_Q16 = 0; } else if (Complexity < 6) { pitchEstimationComplexity = 1; pitchEstimationThreshold_Q16 = 48497; pitchEstimationLPCOrder = 10; shapingLPCOrder = 12; la_shape = 5 * fs_kHz; nStatesDelayedDecision = 2; useInterpolatedNLSFs = 1; LTPQuantLowComplexity = 0; NLSF_MSVQ_Survivors = 8; warping_Q16 = fs_kHz * 983; } else if (Complexity < 8) { pitchEstimationComplexity = 1; pitchEstimationThreshold_Q16 = 47186; pitchEstimationLPCOrder = 12; shapingLPCOrder = 14; la_shape = 5 * fs_kHz; nStatesDelayedDecision = 3; useInterpolatedNLSFs = 1; LTPQuantLowComplexity = 0; NLSF_MSVQ_Survivors = 16; warping_Q16 = fs_kHz * 983; } else { pitchEstimationComplexity = 2; pitchEstimationThreshold_Q16 = 45875; pitchEstimationLPCOrder = 16; shapingLPCOrder = 16; la_shape = 5 * fs_kHz; nStatesDelayedDecision = 4; useInterpolatedNLSFs = 1; LTPQuantLowComplexity = 0; NLSF_MSVQ_Survivors = 32; warping_Q16 = fs_kHz * 983; } pitchEstimationLPCOrder = Inlines.silk_min_int(pitchEstimationLPCOrder, predictLPCOrder); shapeWinLength = 5 * fs_kHz + 2 * la_shape; this.Complexity = Complexity; return 0; } private int silk_setup_LBRR(int TargetRate_bps) { int sILK_NO_ERROR = SilkError.SILK_NO_ERROR; int lBRR_enabled = LBRR_enabled; LBRR_enabled = 0; if (useInBandFEC != 0 && PacketLoss_perc > 0) { int a = ((fs_kHz == 8) ? 12000 : ((fs_kHz != 12) ? 16000 : 14000)); a = Inlines.silk_SMULWB(Inlines.silk_MUL(a, 125 - Inlines.silk_min(PacketLoss_perc, 25)), 655); if (TargetRate_bps > a) { if (lBRR_enabled == 0) { LBRR_GainIncreases = 7; } else { LBRR_GainIncreases = Inlines.silk_max_int(7 - Inlines.silk_SMULWB(PacketLoss_perc, 26214), 2); } LBRR_enabled = 1; } } return sILK_NO_ERROR; } internal int silk_control_audio_bandwidth(EncControlState encControl) { int num = fs_kHz; int num2 = Inlines.silk_SMULBB(num, 1000); if (num2 == 0) { num2 = Inlines.silk_min(desiredInternal_fs_Hz, API_fs_Hz); num = Inlines.silk_DIV32_16(num2, 1000); } else if (num2 > API_fs_Hz || num2 > maxInternal_fs_Hz || num2 < minInternal_fs_Hz) { num2 = API_fs_Hz; num2 = Inlines.silk_min(num2, maxInternal_fs_Hz); num2 = Inlines.silk_max(num2, minInternal_fs_Hz); num = Inlines.silk_DIV32_16(num2, 1000); } else { if (sLP.transition_frame_no >= 256) { sLP.mode = 0; } if (allow_bandwidth_switch != 0 || encControl.opusCanSwitch != 0) { if (Inlines.silk_SMULBB(fs_kHz, 1000) > desiredInternal_fs_Hz) { if (sLP.mode == 0) { sLP.transition_frame_no = 256; Arrays.MemSetInt(sLP.In_LP_State, 0, 2); } if (encControl.opusCanSwitch != 0) { sLP.mode = 0; num = ((fs_kHz == 16) ? 12 : 8); } else if (sLP.transition_frame_no <= 0) { encControl.switchReady = 1; encControl.maxBits -= encControl.maxBits * 5 / (encControl.payloadSize_ms + 5); } else { sLP.mode = -2; } } else if (Inlines.silk_SMULBB(fs_kHz, 1000) < desiredInternal_fs_Hz) { if (encControl.opusCanSwitch != 0) { num = ((fs_kHz == 8) ? 12 : 16); sLP.transition_frame_no = 0; Arrays.MemSetInt(sLP.In_LP_State, 0, 2); sLP.mode = 1; } else if (sLP.mode == 0) { encControl.switchReady = 1; encControl.maxBits -= encControl.maxBits * 5 / (encControl.payloadSize_ms + 5); } else { sLP.mode = 1; } } else if (sLP.mode < 0) { sLP.mode = 1; } } } return num; } internal int silk_control_SNR(int TargetRate_bps) { int sILK_NO_ERROR = SilkError.SILK_NO_ERROR; TargetRate_bps = Inlines.silk_LIMIT(TargetRate_bps, 5000, 80000); if (TargetRate_bps != this.TargetRate_bps) { this.TargetRate_bps = TargetRate_bps; int[] array = ((fs_kHz == 8) ? Tables.silk_TargetRate_table_NB : ((fs_kHz != 12) ? Tables.silk_TargetRate_table_WB : Tables.silk_TargetRate_table_MB)); if (nb_subfr == 2) { TargetRate_bps -= 2200; } for (int i = 1; i < 8; i++) { if (TargetRate_bps <= array[i]) { int a = Inlines.silk_DIV32(Inlines.silk_LSHIFT(TargetRate_bps - array[i - 1], 6), array[i] - array[i - 1]); SNR_dB_Q7 = Inlines.silk_LSHIFT(Tables.silk_SNR_table_Q1[i - 1], 6) + Inlines.silk_MUL(a, Tables.silk_SNR_table_Q1[i] - Tables.silk_SNR_table_Q1[i - 1]); break; } } } return sILK_NO_ERROR; } internal void silk_encode_do_VAD() { VoiceActivityDetection.silk_VAD_GetSA_Q8(this, inputBuf, 1); if (speech_activity_Q8 < 13) { indices.signalType = 0; noSpeechCounter++; if (noSpeechCounter < 10) { inDTX = 0; } else if (noSpeechCounter > 30) { noSpeechCounter = 10; inDTX = 0; } VAD_flags[nFramesEncoded] = 0; } else { noSpeechCounter = 0; inDTX = 0; indices.signalType = 1; VAD_flags[nFramesEncoded] = 1; } } internal int silk_encode_frame(BoxedValueInt pnBytesOut, EntropyCoder psRangeEnc, Span encodedDataOut, int condCoding, int maxBits, int useCBR) { SilkEncoderControl silkEncoderControl = new SilkEncoderControl(); int result = 0; EntropyCoder entropyCoder = new EntropyCoder(); EntropyCoder entropyCoder2 = new EntropyCoder(); SilkNSQState silkNSQState = new SilkNSQState(); SilkNSQState silkNSQState2 = new SilkNSQState(); sbyte lastGainIndex = 0; int num3; int num2; int num; int num4 = (num3 = (num2 = (num = 0))); indices.Seed = (sbyte)(frameCounter++ & 3); int num5 = ltp_mem_length; sLP.silk_LP_variable_cutoff(inputBuf, 1, frame_length); Arrays.MemCopy(inputBuf, 1, x_buf, num5 + 5 * fs_kHz, frame_length); if (prefillFlag == 0) { short[] array = new short[la_pitch + frame_length + ltp_mem_length]; int pitch_res_ptr = ltp_mem_length; FindPitchLags.silk_find_pitch_lags(this, silkEncoderControl, array, x_buf, num5); NoiseShapeAnalysis.silk_noise_shape_analysis(this, silkEncoderControl, array, pitch_res_ptr, x_buf, num5); FindPredCoefs.silk_find_pred_coefs(this, silkEncoderControl, array, x_buf, num5, condCoding); ProcessGains.silk_process_gains(this, silkEncoderControl, condCoding); int[] array2 = new int[frame_length]; Filters.silk_prefilter(this, silkEncoderControl, array2, x_buf, num5); silk_LBRR_encode(silkEncoderControl, array2, condCoding); int num6 = 6; short num7 = 256; int num8 = 0; int num9 = 0; int num10 = GainQuantization.silk_gains_ID(indices.GainsIndices, nb_subfr); int num11 = -1; int num12 = -1; entropyCoder.Assign(psRangeEnc); silkNSQState.Assign(sNSQ); sbyte seed = indices.Seed; short num13 = ec_prevLagIndex; int num14 = ec_prevSignalType; byte[] array3 = new byte[1275]; int num15 = 0; while (true) { int num16; if (num10 == num11) { num16 = num4; } else if (num10 == num12) { num16 = num3; } else { if (num15 > 0) { psRangeEnc.Assign(entropyCoder); sNSQ.Assign(silkNSQState); indices.Seed = seed; ec_prevLagIndex = num13; ec_prevSignalType = num14; } if (nStatesDelayedDecision > 1 || warping_Q16 > 0) { sNSQ.silk_NSQ_del_dec(this, indices, array2, pulses, silkEncoderControl.PredCoef_Q12, silkEncoderControl.LTPCoef_Q14, silkEncoderControl.AR2_Q13, silkEncoderControl.HarmShapeGain_Q14, silkEncoderControl.Tilt_Q14, silkEncoderControl.LF_shp_Q14, silkEncoderControl.Gains_Q16, silkEncoderControl.pitchL, silkEncoderControl.Lambda_Q10, silkEncoderControl.LTP_scale_Q14); } else { sNSQ.silk_NSQ(this, indices, array2, pulses, silkEncoderControl.PredCoef_Q12, silkEncoderControl.LTPCoef_Q14, silkEncoderControl.AR2_Q13, silkEncoderControl.HarmShapeGain_Q14, silkEncoderControl.Tilt_Q14, silkEncoderControl.LF_shp_Q14, silkEncoderControl.Gains_Q16, silkEncoderControl.pitchL, silkEncoderControl.Lambda_Q10, silkEncoderControl.LTP_scale_Q14); } EncodeIndices.silk_encode_indices(this, psRangeEnc, encodedDataOut, nFramesEncoded, 0, condCoding); EncodePulses.silk_encode_pulses(psRangeEnc, encodedDataOut, indices.signalType, indices.quantOffsetType, pulses, frame_length); num16 = psRangeEnc.tell(); if (useCBR == 0 && num15 == 0 && num16 <= maxBits) { break; } } if (num15 == num6) { if (num8 != 0 && (num10 == num11 || num16 > maxBits)) { psRangeEnc.Assign(entropyCoder2); array3.AsSpan(0, (int)entropyCoder2.offs).CopyTo(encodedDataOut); sNSQ.Assign(silkNSQState2); sShape.LastGainIndex = lastGainIndex; } break; } if (num16 > maxBits) { if (num8 == 0 && num15 >= 2) { silkEncoderControl.Lambda_Q10 = Inlines.silk_ADD_RSHIFT32(silkEncoderControl.Lambda_Q10, silkEncoderControl.Lambda_Q10, 1); num9 = 0; num12 = -1; } else { num9 = 1; num3 = num16; num = num7; num12 = num10; } } else { if (num16 >= maxBits - 5) { break; } num8 = 1; num4 = num16; num2 = num7; if (num10 != num11) { num11 = num10; entropyCoder2.Assign(psRangeEnc); encodedDataOut.Slice(0, (int)psRangeEnc.offs).CopyTo(array3); silkNSQState2.Assign(sNSQ); lastGainIndex = sShape.LastGainIndex; } } if ((num8 & num9) == 0) { int a = Inlines.silk_log2lin(Inlines.silk_LSHIFT(num16 - maxBits, 7) / frame_length + 2048); a = Inlines.silk_min_32(a, 131072); if (num16 > maxBits) { a = Inlines.silk_max_32(a, 85197); } num7 = (short)Inlines.silk_SMULWB(a, num7); } else { num7 = (short)(num2 + Inlines.silk_DIV32_16(Inlines.silk_MUL(num - num2, maxBits - num4), num3 - num4)); if (num7 > Inlines.silk_ADD_RSHIFT32(num2, num - num2, 2)) { num7 = (short)Inlines.silk_ADD_RSHIFT32(num2, num - num2, 2); } else if (num7 < Inlines.silk_SUB_RSHIFT32(num, num - num2, 2)) { num7 = (short)Inlines.silk_SUB_RSHIFT32(num, num - num2, 2); } } for (int i = 0; i < nb_subfr; i++) { silkEncoderControl.Gains_Q16[i] = Inlines.silk_LSHIFT_SAT32(Inlines.silk_SMULWB(silkEncoderControl.GainsUnq_Q16[i], num7), 8); } sShape.LastGainIndex = silkEncoderControl.lastGainIndexPrev; BoxedValueSbyte boxedValueSbyte = new BoxedValueSbyte(sShape.LastGainIndex); GainQuantization.silk_gains_quant(indices.GainsIndices, silkEncoderControl.Gains_Q16, boxedValueSbyte, (condCoding == 2) ? 1 : 0, nb_subfr); sShape.LastGainIndex = boxedValueSbyte.Val; num10 = GainQuantization.silk_gains_ID(indices.GainsIndices, nb_subfr); num15++; } } Arrays.MemMoveShort(x_buf, frame_length, 0, ltp_mem_length + 5 * fs_kHz); if (prefillFlag != 0) { pnBytesOut.Val = 0; return result; } prevLag = silkEncoderControl.pitchL[nb_subfr - 1]; prevSignalType = indices.signalType; first_frame_after_reset = 0; pnBytesOut.Val = Inlines.silk_RSHIFT(psRangeEnc.tell() + 7, 3); return result; } internal void silk_LBRR_encode(SilkEncoderControl thisCtrl, int[] xfw_Q3, int condCoding) { int[] array = new int[nb_subfr]; SideInfoIndices sideInfoIndices = indices_LBRR[nFramesEncoded]; SilkNSQState silkNSQState = new SilkNSQState(); if (LBRR_enabled != 0 && speech_activity_Q8 > 77) { LBRR_flags[nFramesEncoded] = 1; silkNSQState.Assign(sNSQ); sideInfoIndices.Assign(indices); Arrays.MemCopy(thisCtrl.Gains_Q16, 0, array, 0, nb_subfr); if (nFramesEncoded == 0 || LBRR_flags[nFramesEncoded - 1] == 0) { LBRRprevLastGainIndex = sShape.LastGainIndex; sideInfoIndices.GainsIndices[0] = (sbyte)(sideInfoIndices.GainsIndices[0] + LBRR_GainIncreases); sideInfoIndices.GainsIndices[0] = (sbyte)Inlines.silk_min_int(sideInfoIndices.GainsIndices[0], 63); } BoxedValueSbyte boxedValueSbyte = new BoxedValueSbyte(LBRRprevLastGainIndex); GainQuantization.silk_gains_dequant(thisCtrl.Gains_Q16, sideInfoIndices.GainsIndices, boxedValueSbyte, (condCoding == 2) ? 1 : 0, nb_subfr); LBRRprevLastGainIndex = boxedValueSbyte.Val; if (nStatesDelayedDecision > 1 || warping_Q16 > 0) { silkNSQState.silk_NSQ_del_dec(this, sideInfoIndices, xfw_Q3, pulses_LBRR[nFramesEncoded], thisCtrl.PredCoef_Q12, thisCtrl.LTPCoef_Q14, thisCtrl.AR2_Q13, thisCtrl.HarmShapeGain_Q14, thisCtrl.Tilt_Q14, thisCtrl.LF_shp_Q14, thisCtrl.Gains_Q16, thisCtrl.pitchL, thisCtrl.Lambda_Q10, thisCtrl.LTP_scale_Q14); } else { silkNSQState.silk_NSQ(this, sideInfoIndices, xfw_Q3, pulses_LBRR[nFramesEncoded], thisCtrl.PredCoef_Q12, thisCtrl.LTPCoef_Q14, thisCtrl.AR2_Q13, thisCtrl.HarmShapeGain_Q14, thisCtrl.Tilt_Q14, thisCtrl.LF_shp_Q14, thisCtrl.Gains_Q16, thisCtrl.pitchL, thisCtrl.Lambda_Q10, thisCtrl.LTP_scale_Q14); } Arrays.MemCopy(array, 0, thisCtrl.Gains_Q16, 0, nb_subfr); } } } internal class SilkDecoder { internal readonly SilkChannelDecoder[] channel_state = new SilkChannelDecoder[2]; internal readonly StereoDecodeState sStereo = new StereoDecodeState(); internal int nChannelsAPI; internal int nChannelsInternal; internal int prev_decode_only_middle; internal SilkDecoder() { for (int i = 0; i < 2; i++) { channel_state[i] = new SilkChannelDecoder(); } } internal void Reset() { for (int i = 0; i < 2; i++) { channel_state[i].Reset(); } sStereo.Reset(); nChannelsAPI = 0; nChannelsInternal = 0; prev_decode_only_middle = 0; } } internal class SilkDecoderControl { internal readonly int[] pitchL = new int[4]; internal readonly int[] Gains_Q16 = new int[4]; internal readonly short[][] PredCoef_Q12 = Arrays.InitTwoDimensionalArray(2, 16); internal readonly short[] LTPCoef_Q14 = new short[20]; internal int LTP_scale_Q14; internal void Reset() { Arrays.MemSetInt(pitchL, 0, 4); Arrays.MemSetInt(Gains_Q16, 0, 4); Arrays.MemSetShort(PredCoef_Q12[0], 0, 16); Arrays.MemSetShort(PredCoef_Q12[1], 0, 16); Arrays.MemSetShort(LTPCoef_Q14, 0, 20); LTP_scale_Q14 = 0; } } internal class SilkEncoder { internal readonly SilkChannelEncoder[] state_Fxx = new SilkChannelEncoder[2]; internal readonly StereoEncodeState sStereo = new StereoEncodeState(); internal int nBitsUsedLBRR; internal int nBitsExceeded; internal int nChannelsAPI; internal int nChannelsInternal; internal int nPrevChannelsInternal; internal int timeSinceSwitchAllowed_ms; internal int allowBandwidthSwitch; internal int prev_decode_only_middle; internal SilkEncoder() { for (int i = 0; i < 2; i++) { state_Fxx[i] = new SilkChannelEncoder(); } } internal void Reset() { for (int i = 0; i < 2; i++) { state_Fxx[i].Reset(); } sStereo.Reset(); nBitsUsedLBRR = 0; nBitsExceeded = 0; nChannelsAPI = 0; nChannelsInternal = 0; nPrevChannelsInternal = 0; timeSinceSwitchAllowed_ms = 0; allowBandwidthSwitch = 0; prev_decode_only_middle = 0; } internal static int silk_init_encoder(SilkChannelEncoder psEnc) { psEnc.Reset(); psEnc.variable_HP_smth1_Q15 = Inlines.silk_LSHIFT(Inlines.silk_lin2log(3932160) - 2048, 8); psEnc.variable_HP_smth2_Q15 = psEnc.variable_HP_smth1_Q15; psEnc.first_frame_after_reset = 1; return 0 + VoiceActivityDetection.silk_VAD_Init(psEnc.sVAD); } } internal class SilkEncoderControl { internal readonly int[] Gains_Q16 = new int[4]; internal readonly short[][] PredCoef_Q12 = Arrays.InitTwoDimensionalArray(2, 16); internal readonly short[] LTPCoef_Q14 = new short[20]; internal int LTP_scale_Q14; internal readonly int[] pitchL = new int[4]; internal readonly short[] AR1_Q13 = new short[64]; internal readonly short[] AR2_Q13 = new short[64]; internal readonly int[] LF_shp_Q14 = new int[4]; internal readonly int[] GainsPre_Q14 = new int[4]; internal readonly int[] HarmBoost_Q14 = new int[4]; internal readonly int[] Tilt_Q14 = new int[4]; internal readonly int[] HarmShapeGain_Q14 = new int[4]; internal int Lambda_Q10; internal int input_quality_Q14; internal int coding_quality_Q14; internal int sparseness_Q8; internal int predGain_Q16; internal int LTPredCodGain_Q7; internal readonly int[] ResNrg = new int[4]; internal readonly int[] ResNrgQ = new int[4]; internal readonly int[] GainsUnq_Q16 = new int[4]; internal sbyte lastGainIndexPrev; internal void Reset() { Arrays.MemSetInt(Gains_Q16, 0, 4); Arrays.MemSetShort(PredCoef_Q12[0], 0, 16); Arrays.MemSetShort(PredCoef_Q12[1], 0, 16); Arrays.MemSetShort(LTPCoef_Q14, 0, 20); LTP_scale_Q14 = 0; Arrays.MemSetInt(pitchL, 0, 4); Arrays.MemSetShort(AR1_Q13, 0, 64); Arrays.MemSetShort(AR2_Q13, 0, 64); Arrays.MemSetInt(LF_shp_Q14, 0, 4); Arrays.MemSetInt(GainsPre_Q14, 0, 4); Arrays.MemSetInt(HarmBoost_Q14, 0, 4); Arrays.MemSetInt(Tilt_Q14, 0, 4); Arrays.MemSetInt(HarmShapeGain_Q14, 0, 4); Lambda_Q10 = 0; input_quality_Q14 = 0; coding_quality_Q14 = 0; sparseness_Q8 = 0; predGain_Q16 = 0; LTPredCodGain_Q7 = 0; Arrays.MemSetInt(ResNrg, 0, 4); Arrays.MemSetInt(ResNrgQ, 0, 4); Arrays.MemSetInt(GainsUnq_Q16, 0, 4); lastGainIndexPrev = 0; } } internal class SilkLPState { internal readonly int[] In_LP_State = new int[2]; internal int transition_frame_no; internal int mode; internal void Reset() { In_LP_State[0] = 0; In_LP_State[1] = 0; transition_frame_no = 0; mode = 0; } internal void silk_LP_variable_cutoff(short[] frame, int frame_ptr, int frame_length) { int[] b_Q = new int[3]; int[] a_Q = new int[2]; int num = 0; int num2 = 0; if (mode != 0) { num = Inlines.silk_LSHIFT(256 - transition_frame_no, 10); num2 = Inlines.silk_RSHIFT(num, 16); num -= Inlines.silk_LSHIFT(num2, 16); Filters.silk_LP_interpolate_filter_taps(b_Q, a_Q, num2, num); transition_frame_no = Inlines.silk_LIMIT(transition_frame_no + mode, 0, 256); Filters.silk_biquad_alt(frame, frame_ptr, b_Q, a_Q, In_LP_State, frame, frame_ptr, frame_length, 1); } } } internal class SilkNSQState { private class NSQ_del_dec_struct { internal readonly int[] sLPC_Q14 = new int[80 + SilkConstants.NSQ_LPC_BUF_LENGTH]; internal readonly int[] RandState = new int[32]; internal readonly int[] Q_Q10 = new int[32]; internal readonly int[] Xq_Q14 = new int[32]; internal readonly int[] Pred_Q15 = new int[32]; internal readonly int[] Shape_Q14 = new int[32]; internal int[] sAR2_Q14; internal int LF_AR_Q14; internal int Seed; internal int SeedInit; internal int RD_Q10; internal NSQ_del_dec_struct(int shapingOrder) { sAR2_Q14 = new int[shapingOrder]; } internal void PartialCopyFrom(NSQ_del_dec_struct other, int q14Offset) { Buffer.BlockCopy(other.sLPC_Q14, q14Offset * 4, sLPC_Q14, q14Offset * 4, (80 + SilkConstants.NSQ_LPC_BUF_LENGTH - q14Offset) * 4); Buffer.BlockCopy(other.RandState, 0, RandState, 0, 128); Buffer.BlockCopy(other.Q_Q10, 0, Q_Q10, 0, 128); Buffer.BlockCopy(other.Xq_Q14, 0, Xq_Q14, 0, 128); Buffer.BlockCopy(other.Pred_Q15, 0, Pred_Q15, 0, 128); Buffer.BlockCopy(other.Shape_Q14, 0, Shape_Q14, 0, 128); Buffer.BlockCopy(other.sAR2_Q14, 0, sAR2_Q14, 0, sAR2_Q14.Length * 4); LF_AR_Q14 = other.LF_AR_Q14; Seed = other.Seed; SeedInit = other.SeedInit; RD_Q10 = other.RD_Q10; } internal void Assign(NSQ_del_dec_struct other) { PartialCopyFrom(other, 0); } } private struct NSQ_sample_struct { internal int Q_Q10; internal int RD_Q10; internal int xq_Q14; internal int LF_AR_Q14; internal int sLTP_shp_Q14; internal int LPC_exc_Q14; } internal readonly short[] xq = new short[640]; internal readonly int[] sLTP_shp_Q14 = new int[640]; internal readonly int[] sLPC_Q14 = new int[80 + SilkConstants.NSQ_LPC_BUF_LENGTH]; internal readonly int[] sAR2_Q14 = new int[16]; internal int sLF_AR_shp_Q14; internal int lagPrev; internal int sLTP_buf_idx; internal int sLTP_shp_buf_idx; internal int rand_seed; internal int prev_gain_Q16; internal int rewhite_flag; internal void Reset() { Arrays.MemSetShort(xq, 0, 640); Arrays.MemSetInt(sLTP_shp_Q14, 0, 640); Arrays.MemSetInt(sLPC_Q14, 0, 80 + SilkConstants.NSQ_LPC_BUF_LENGTH); Arrays.MemSetInt(sAR2_Q14, 0, 16); sLF_AR_shp_Q14 = 0; lagPrev = 0; sLTP_buf_idx = 0; sLTP_shp_buf_idx = 0; rand_seed = 0; prev_gain_Q16 = 0; rewhite_flag = 0; } internal void Assign(SilkNSQState other) { sLF_AR_shp_Q14 = other.sLF_AR_shp_Q14; lagPrev = other.lagPrev; sLTP_buf_idx = other.sLTP_buf_idx; sLTP_shp_buf_idx = other.sLTP_shp_buf_idx; rand_seed = other.rand_seed; prev_gain_Q16 = other.prev_gain_Q16; rewhite_flag = other.rewhite_flag; Arrays.MemCopy(other.xq, 0, xq, 0, 640); Arrays.MemCopy(other.sLTP_shp_Q14, 0, sLTP_shp_Q14, 0, 640); Arrays.MemCopy(other.sLPC_Q14, 0, sLPC_Q14, 0, 80 + SilkConstants.NSQ_LPC_BUF_LENGTH); Arrays.MemCopy(other.sAR2_Q14, 0, sAR2_Q14, 0, 16); } internal void silk_NSQ(SilkChannelEncoder psEncC, SideInfoIndices psIndices, int[] x_Q3, sbyte[] pulses, short[][] PredCoef_Q12, short[] LTPCoef_Q14, short[] AR2_Q13, int[] HarmShapeGain_Q14, int[] Tilt_Q14, int[] LF_shp_Q14, int[] Gains_Q16, int[] pitchL, int Lambda_Q10, int LTP_scale_Q14) { int num = 0; int num2 = 0; rand_seed = psIndices.Seed; int num3 = lagPrev; int offset_Q = Tables.silk_Quantization_Offsets_Q10[psIndices.signalType >> 1][psIndices.quantOffsetType]; int num4 = ((psIndices.NLSFInterpCoef_Q2 != 4) ? 1 : 0); int[] sLTP_Q = new int[psEncC.ltp_mem_length + psEncC.frame_length]; short[] array = new short[psEncC.ltp_mem_length + psEncC.frame_length]; int[] x_sc_Q = new int[psEncC.subfr_length]; sLTP_shp_buf_idx = psEncC.ltp_mem_length; sLTP_buf_idx = psEncC.ltp_mem_length; int num5 = psEncC.ltp_mem_length; for (int i = 0; i < psEncC.nb_subfr; i++) { int num6 = (i >> 1) | (1 - num4); int b_Q14_ptr = i * 5; int aR_shp_Q13_ptr = i * 16; int num7 = Inlines.silk_RSHIFT(HarmShapeGain_Q14[i], 2); num7 |= Inlines.silk_LSHIFT(Inlines.silk_RSHIFT(HarmShapeGain_Q14[i], 1), 16); rewhite_flag = 0; if (psIndices.signalType == 2) { num3 = pitchL[i]; if ((i & (3 - Inlines.silk_LSHIFT(num4, 1))) == 0) { int num8 = psEncC.ltp_mem_length - num3 - psEncC.predictLPCOrder - 2; Filters.silk_LPC_analysis_filter(array, num8, xq, num8 + i * psEncC.subfr_length, PredCoef_Q12[num6], 0, psEncC.ltp_mem_length - num8, psEncC.predictLPCOrder); rewhite_flag = 1; sLTP_buf_idx = psEncC.ltp_mem_length; } } silk_nsq_scale_states(psEncC, x_Q3, num2, x_sc_Q, array, sLTP_Q, i, LTP_scale_Q14, Gains_Q16, pitchL, psIndices.signalType); silk_noise_shape_quantizer(psIndices.signalType, x_sc_Q, pulses, num, xq, num5, sLTP_Q, PredCoef_Q12[num6], LTPCoef_Q14, b_Q14_ptr, AR2_Q13, aR_shp_Q13_ptr, num3, num7, Tilt_Q14[i], LF_shp_Q14[i], Gains_Q16[i], Lambda_Q10, offset_Q, psEncC.subfr_length, psEncC.shapingLPCOrder, psEncC.predictLPCOrder); num2 += psEncC.subfr_length; num += psEncC.subfr_length; num5 += psEncC.subfr_length; } lagPrev = pitchL[psEncC.nb_subfr - 1]; Arrays.MemMoveShort(xq, psEncC.frame_length, 0, psEncC.ltp_mem_length); Arrays.MemMoveInt(sLTP_shp_Q14, psEncC.frame_length, 0, psEncC.ltp_mem_length); } private void silk_noise_shape_quantizer(int signalType, int[] x_sc_Q10, sbyte[] pulses, int pulses_ptr, short[] xq, int xq_ptr, int[] sLTP_Q15, short[] a_Q12, short[] b_Q14, int b_Q14_ptr, short[] AR_shp_Q13, int AR_shp_Q13_ptr, int lag, int HarmShapeFIRPacked_Q14, int Tilt_Q14, int LF_shp_Q14, int Gain_Q16, int Lambda_Q10, int offset_Q10, int length, int shapingLPCOrder, int predictLPCOrder) { int num = sLTP_shp_buf_idx - lag + 1; int num2 = sLTP_buf_idx - lag + 2; int b = Inlines.silk_RSHIFT(Gain_Q16, 6); int num3 = SilkConstants.NSQ_LPC_BUF_LENGTH - 1; for (int i = 0; i < length; i++) { rand_seed = Inlines.silk_RAND(rand_seed); int a = Inlines.silk_RSHIFT(predictLPCOrder, 1); a = Inlines.silk_SMLAWB(a, sLPC_Q14[num3], a_Q12[0]); a = Inlines.silk_SMLAWB(a, sLPC_Q14[num3 - 1], a_Q12[1]); a = Inlines.silk_SMLAWB(a, sLPC_Q14[num3 - 2], a_Q12[2]); a = Inlines.silk_SMLAWB(a, sLPC_Q14[num3 - 3], a_Q12[3]); a = Inlines.silk_SMLAWB(a, sLPC_Q14[num3 - 4], a_Q12[4]); a = Inlines.silk_SMLAWB(a, sLPC_Q14[num3 - 5], a_Q12[5]); a = Inlines.silk_SMLAWB(a, sLPC_Q14[num3 - 6], a_Q12[6]); a = Inlines.silk_SMLAWB(a, sLPC_Q14[num3 - 7], a_Q12[7]); a = Inlines.silk_SMLAWB(a, sLPC_Q14[num3 - 8], a_Q12[8]); a = Inlines.silk_SMLAWB(a, sLPC_Q14[num3 - 9], a_Q12[9]); if (predictLPCOrder == 16) { a = Inlines.silk_SMLAWB(a, sLPC_Q14[num3 - 10], a_Q12[10]); a = Inlines.silk_SMLAWB(a, sLPC_Q14[num3 - 11], a_Q12[11]); a = Inlines.silk_SMLAWB(a, sLPC_Q14[num3 - 12], a_Q12[12]); a = Inlines.silk_SMLAWB(a, sLPC_Q14[num3 - 13], a_Q12[13]); a = Inlines.silk_SMLAWB(a, sLPC_Q14[num3 - 14], a_Q12[14]); a = Inlines.silk_SMLAWB(a, sLPC_Q14[num3 - 15], a_Q12[15]); } int a2; if (signalType == 2) { a2 = 2; a2 = Inlines.silk_SMLAWB(a2, sLTP_Q15[num2], b_Q14[b_Q14_ptr]); a2 = Inlines.silk_SMLAWB(a2, sLTP_Q15[num2 - 1], b_Q14[b_Q14_ptr + 1]); a2 = Inlines.silk_SMLAWB(a2, sLTP_Q15[num2 - 2], b_Q14[b_Q14_ptr + 2]); a2 = Inlines.silk_SMLAWB(a2, sLTP_Q15[num2 - 3], b_Q14[b_Q14_ptr + 3]); a2 = Inlines.silk_SMLAWB(a2, sLTP_Q15[num2 - 4], b_Q14[b_Q14_ptr + 4]); num2++; } else { a2 = 0; } int num4 = sLPC_Q14[num3]; int num5 = sAR2_Q14[0]; sAR2_Q14[0] = num4; int a3 = Inlines.silk_RSHIFT(shapingLPCOrder, 1); a3 = Inlines.silk_SMLAWB(a3, num4, AR_shp_Q13[AR_shp_Q13_ptr]); for (int j = 2; j < shapingLPCOrder; j += 2) { num4 = sAR2_Q14[j - 1]; sAR2_Q14[j - 1] = num5; a3 = Inlines.silk_SMLAWB(a3, num5, AR_shp_Q13[AR_shp_Q13_ptr + j - 1]); num5 = sAR2_Q14[j]; sAR2_Q14[j] = num4; a3 = Inlines.silk_SMLAWB(a3, num4, AR_shp_Q13[AR_shp_Q13_ptr + j]); } sAR2_Q14[shapingLPCOrder - 1] = num5; a3 = Inlines.silk_SMLAWB(a3, num5, AR_shp_Q13[AR_shp_Q13_ptr + shapingLPCOrder - 1]); a3 = Inlines.silk_LSHIFT32(a3, 1); a3 = Inlines.silk_SMLAWB(a3, sLF_AR_shp_Q14, Tilt_Q14); int a4 = Inlines.silk_SMULWB(sLTP_shp_Q14[sLTP_shp_buf_idx - 1], LF_shp_Q14); a4 = Inlines.silk_SMLAWT(a4, sLF_AR_shp_Q14, LF_shp_Q14); num5 = Inlines.silk_SUB32(Inlines.silk_LSHIFT32(a, 2), a3); num5 = Inlines.silk_SUB32(num5, a4); if (lag > 0) { int a5 = Inlines.silk_SMULWB(Inlines.silk_ADD32(sLTP_shp_Q14[num], sLTP_shp_Q14[num - 2]), HarmShapeFIRPacked_Q14); a5 = Inlines.silk_SMLAWT(a5, sLTP_shp_Q14[num - 1], HarmShapeFIRPacked_Q14); a5 = Inlines.silk_LSHIFT(a5, 1); num++; num4 = Inlines.silk_SUB32(a2, a5); num5 = Inlines.silk_ADD_LSHIFT32(num4, num5, 1); num5 = Inlines.silk_RSHIFT_ROUND(num5, 3); } else { num5 = Inlines.silk_RSHIFT_ROUND(num5, 2); } int num6 = Inlines.silk_SUB32(x_sc_Q10[i], num5); if (rand_seed < 0) { num6 = -num6; } num6 = Inlines.silk_LIMIT_32(num6, -31744, 30720); int a6 = Inlines.silk_SUB32(num6, offset_Q10); int num7 = Inlines.silk_RSHIFT(a6, 10); int num8; int a7; int a8; if (num7 > 0) { a6 = Inlines.silk_SUB32(Inlines.silk_LSHIFT(num7, 10), 80); a6 = Inlines.silk_ADD32(a6, offset_Q10); num8 = Inlines.silk_ADD32(a6, 1024); a7 = Inlines.silk_SMULBB(a6, Lambda_Q10); a8 = Inlines.silk_SMULBB(num8, Lambda_Q10); } else { switch (num7) { case 0: a6 = offset_Q10; num8 = Inlines.silk_ADD32(a6, 944); a7 = Inlines.silk_SMULBB(a6, Lambda_Q10); a8 = Inlines.silk_SMULBB(num8, Lambda_Q10); break; case -1: num8 = offset_Q10; a6 = Inlines.silk_SUB32(num8, 944); a7 = Inlines.silk_SMULBB(-a6, Lambda_Q10); a8 = Inlines.silk_SMULBB(num8, Lambda_Q10); break; default: a6 = Inlines.silk_ADD32(Inlines.silk_LSHIFT(num7, 10), 80); a6 = Inlines.silk_ADD32(a6, offset_Q10); num8 = Inlines.silk_ADD32(a6, 1024); a7 = Inlines.silk_SMULBB(-a6, Lambda_Q10); a8 = Inlines.silk_SMULBB(-num8, Lambda_Q10); break; } } int num9 = Inlines.silk_SUB32(num6, a6); a7 = Inlines.silk_SMLABB(a7, num9, num9); num9 = Inlines.silk_SUB32(num6, num8); a8 = Inlines.silk_SMLABB(a8, num9, num9); if (a8 < a7) { a6 = num8; } pulses[pulses_ptr + i] = (sbyte)Inlines.silk_RSHIFT_ROUND(a6, 10); int num10 = Inlines.silk_LSHIFT(a6, 4); if (rand_seed < 0) { num10 = -num10; } int a9 = Inlines.silk_ADD_LSHIFT32(num10, a2, 1); int num11 = Inlines.silk_ADD_LSHIFT32(a9, a, 4); xq[xq_ptr + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(num11, b), 8)); num3++; sLPC_Q14[num3] = num11; int a10 = (sLF_AR_shp_Q14 = Inlines.silk_SUB_LSHIFT32(num11, a3, 2)); sLTP_shp_Q14[sLTP_shp_buf_idx] = Inlines.silk_SUB_LSHIFT32(a10, a4, 2); sLTP_Q15[sLTP_buf_idx] = Inlines.silk_LSHIFT(a9, 1); sLTP_shp_buf_idx++; sLTP_buf_idx++; rand_seed = Inlines.silk_ADD32_ovflw(rand_seed, pulses[pulses_ptr + i]); } Arrays.MemCopy(sLPC_Q14, length, sLPC_Q14, 0, SilkConstants.NSQ_LPC_BUF_LENGTH); } private void silk_nsq_scale_states(SilkChannelEncoder psEncC, int[] x_Q3, int x_Q3_ptr, int[] x_sc_Q10, short[] sLTP, int[] sLTP_Q15, int subfr, int LTP_scale_Q14, int[] Gains_Q16, int[] pitchL, int signal_type) { int num = pitchL[subfr]; int num2 = Inlines.silk_INVERSE32_varQ(Inlines.silk_max(Gains_Q16[subfr], 1), 47); int num3 = ((Gains_Q16[subfr] == prev_gain_Q16) ? 65536 : Inlines.silk_DIV32_varQ(prev_gain_Q16, Gains_Q16[subfr], 16)); int b = Inlines.silk_RSHIFT_ROUND(num2, 8); for (int i = 0; i < psEncC.subfr_length; i++) { x_sc_Q10[i] = Inlines.silk_SMULWW(x_Q3[x_Q3_ptr + i], b); } prev_gain_Q16 = Gains_Q16[subfr]; if (rewhite_flag != 0) { if (subfr == 0) { num2 = Inlines.silk_LSHIFT(Inlines.silk_SMULWB(num2, LTP_scale_Q14), 2); } for (int i = sLTP_buf_idx - num - 2; i < sLTP_buf_idx; i++) { sLTP_Q15[i] = Inlines.silk_SMULWB(num2, sLTP[i]); } } if (num3 == 65536) { return; } for (int i = sLTP_shp_buf_idx - psEncC.ltp_mem_length; i < sLTP_shp_buf_idx; i++) { sLTP_shp_Q14[i] = Inlines.silk_SMULWW(num3, sLTP_shp_Q14[i]); } if (signal_type == 2 && rewhite_flag == 0) { for (int i = sLTP_buf_idx - num - 2; i < sLTP_buf_idx; i++) { sLTP_Q15[i] = Inlines.silk_SMULWW(num3, sLTP_Q15[i]); } } sLF_AR_shp_Q14 = Inlines.silk_SMULWW(num3, sLF_AR_shp_Q14); for (int i = 0; i < SilkConstants.NSQ_LPC_BUF_LENGTH; i++) { sLPC_Q14[i] = Inlines.silk_SMULWW(num3, sLPC_Q14[i]); } for (int i = 0; i < 16; i++) { sAR2_Q14[i] = Inlines.silk_SMULWW(num3, sAR2_Q14[i]); } } internal void silk_NSQ_del_dec(SilkChannelEncoder psEncC, SideInfoIndices psIndices, int[] x_Q3, sbyte[] pulses, short[][] PredCoef_Q12, short[] LTPCoef_Q14, short[] AR2_Q13, int[] HarmShapeGain_Q14, int[] Tilt_Q14, int[] LF_shp_Q14, int[] Gains_Q16, int[] pitchL, int Lambda_Q10, int LTP_scale_Q14) { int num = 0; int num2 = 0; int num3 = lagPrev; NSQ_del_dec_struct[] array = new NSQ_del_dec_struct[psEncC.nStatesDelayedDecision]; for (int i = 0; i < psEncC.nStatesDelayedDecision; i++) { array[i] = new NSQ_del_dec_struct(psEncC.shapingLPCOrder); } NSQ_del_dec_struct nSQ_del_dec_struct; for (int j = 0; j < psEncC.nStatesDelayedDecision; j++) { nSQ_del_dec_struct = array[j]; nSQ_del_dec_struct.Seed = (j + psIndices.Seed) & 3; nSQ_del_dec_struct.SeedInit = nSQ_del_dec_struct.Seed; nSQ_del_dec_struct.RD_Q10 = 0; nSQ_del_dec_struct.LF_AR_Q14 = sLF_AR_shp_Q14; nSQ_del_dec_struct.Shape_Q14[0] = sLTP_shp_Q14[psEncC.ltp_mem_length - 1]; Arrays.MemCopy(sLPC_Q14, 0, nSQ_del_dec_struct.sLPC_Q14, 0, SilkConstants.NSQ_LPC_BUF_LENGTH); Arrays.MemCopy(sAR2_Q14, 0, nSQ_del_dec_struct.sAR2_Q14, 0, psEncC.shapingLPCOrder); } int offset_Q = Tables.silk_Quantization_Offsets_Q10[psIndices.signalType >> 1][psIndices.quantOffsetType]; int num4 = 0; int num5 = Inlines.silk_min_int(32, psEncC.subfr_length); if (psIndices.signalType == 2) { for (int j = 0; j < psEncC.nb_subfr; j++) { num5 = Inlines.silk_min_int(num5, pitchL[j] - 2 - 1); } } else if (num3 > 0) { num5 = Inlines.silk_min_int(num5, num3 - 2 - 1); } int num6 = ((psIndices.NLSFInterpCoef_Q2 != 4) ? 1 : 0); int[] sLTP_Q = new int[psEncC.ltp_mem_length + psEncC.frame_length]; short[] array2 = new short[psEncC.ltp_mem_length + psEncC.frame_length]; int[] array3 = new int[psEncC.subfr_length]; int[] delayedGain_Q = new int[32]; int num7 = psEncC.ltp_mem_length; sLTP_shp_buf_idx = psEncC.ltp_mem_length; sLTP_buf_idx = psEncC.ltp_mem_length; int num8 = 0; int rD_Q; int num11; int num12; for (int j = 0; j < psEncC.nb_subfr; j++) { int num9 = (j >> 1) | (1 - num6); int num10 = Inlines.silk_RSHIFT(HarmShapeGain_Q14[j], 2); num10 |= Inlines.silk_LSHIFT(Inlines.silk_RSHIFT(HarmShapeGain_Q14[j], 1), 16); rewhite_flag = 0; if (psIndices.signalType == 2) { num3 = pitchL[j]; if ((j & (3 - Inlines.silk_LSHIFT(num6, 1))) == 0) { if (j == 2) { rD_Q = array[0].RD_Q10; num11 = 0; for (int k = 1; k < psEncC.nStatesDelayedDecision; k++) { if (array[k].RD_Q10 < rD_Q) { rD_Q = array[k].RD_Q10; num11 = k; } } for (int k = 0; k < psEncC.nStatesDelayedDecision; k++) { if (k != num11) { array[k].RD_Q10 += 134217727; } } nSQ_del_dec_struct = array[num11]; num12 = num4 + num5; for (int k = 0; k < num5; k++) { num12 = (num12 - 1) & 0x1F; pulses[num + k - num5] = (sbyte)Inlines.silk_RSHIFT_ROUND(nSQ_del_dec_struct.Q_Q10[num12], 10); xq[num7 + k - num5] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(nSQ_del_dec_struct.Xq_Q14[num12], Gains_Q16[1]), 14)); sLTP_shp_Q14[sLTP_shp_buf_idx - num5 + k] = nSQ_del_dec_struct.Shape_Q14[num12]; } num8 = 0; } int num13 = psEncC.ltp_mem_length - num3 - psEncC.predictLPCOrder - 2; Filters.silk_LPC_analysis_filter(array2, num13, xq, num13 + j * psEncC.subfr_length, PredCoef_Q12[num9], 0, psEncC.ltp_mem_length - num13, psEncC.predictLPCOrder); sLTP_buf_idx = psEncC.ltp_mem_length; rewhite_flag = 1; } } silk_nsq_del_dec_scale_states(psEncC, array, x_Q3, num2, array3, array2, sLTP_Q, j, psEncC.nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices.signalType, num5); BoxedValueInt boxedValueInt = new BoxedValueInt(num4); silk_noise_shape_quantizer_del_dec(array, psIndices.signalType, array3, pulses, num, xq, num7, sLTP_Q, delayedGain_Q, PredCoef_Q12[num9], LTPCoef_Q14, j * 5, AR2_Q13, j * 16, num3, num10, Tilt_Q14[j], LF_shp_Q14[j], Gains_Q16[j], Lambda_Q10, offset_Q, psEncC.subfr_length, num8++, psEncC.shapingLPCOrder, psEncC.predictLPCOrder, psEncC.warping_Q16, psEncC.nStatesDelayedDecision, boxedValueInt, num5); num4 = boxedValueInt.Val; num2 += psEncC.subfr_length; num += psEncC.subfr_length; num7 += psEncC.subfr_length; } rD_Q = array[0].RD_Q10; num11 = 0; for (int j = 1; j < psEncC.nStatesDelayedDecision; j++) { if (array[j].RD_Q10 < rD_Q) { rD_Q = array[j].RD_Q10; num11 = j; } } nSQ_del_dec_struct = array[num11]; psIndices.Seed = (sbyte)nSQ_del_dec_struct.SeedInit; num12 = num4 + num5; int b = Inlines.silk_RSHIFT32(Gains_Q16[psEncC.nb_subfr - 1], 6); for (int k = 0; k < num5; k++) { num12 = (num12 - 1) & 0x1F; pulses[num + k - num5] = (sbyte)Inlines.silk_RSHIFT_ROUND(nSQ_del_dec_struct.Q_Q10[num12], 10); xq[num7 + k - num5] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(nSQ_del_dec_struct.Xq_Q14[num12], b), 8)); sLTP_shp_Q14[sLTP_shp_buf_idx - num5 + k] = nSQ_del_dec_struct.Shape_Q14[num12]; } Arrays.MemCopy(nSQ_del_dec_struct.sLPC_Q14, psEncC.subfr_length, sLPC_Q14, 0, SilkConstants.NSQ_LPC_BUF_LENGTH); Arrays.MemCopy(nSQ_del_dec_struct.sAR2_Q14, 0, sAR2_Q14, 0, psEncC.shapingLPCOrder); sLF_AR_shp_Q14 = nSQ_del_dec_struct.LF_AR_Q14; lagPrev = pitchL[psEncC.nb_subfr - 1]; Arrays.MemMoveShort(xq, psEncC.frame_length, 0, psEncC.ltp_mem_length); Arrays.MemMoveInt(sLTP_shp_Q14, psEncC.frame_length, 0, psEncC.ltp_mem_length); } private void silk_noise_shape_quantizer_del_dec(NSQ_del_dec_struct[] psDelDec, int signalType, int[] x_Q10, sbyte[] pulses, int pulses_ptr, short[] xq, int xq_ptr, int[] sLTP_Q15, int[] delayedGain_Q10, short[] a_Q12, short[] b_Q14, int b_Q14_ptr, short[] AR_shp_Q13, int AR_shp_Q13_ptr, int lag, int HarmShapeFIRPacked_Q14, int Tilt_Q14, int LF_shp_Q14, int Gain_Q16, int Lambda_Q10, int offset_Q10, int length, int subfr, int shapingLPCOrder, int predictLPCOrder, int warping_Q16, int nStatesDelayedDecision, BoxedValueInt smpl_buf_idx, int decisionDelay) { NSQ_sample_struct[] array = new NSQ_sample_struct[2 * nStatesDelayedDecision]; for (int i = 0; i < 2 * nStatesDelayedDecision; i++) { array[i] = default(NSQ_sample_struct); } int num = sLTP_shp_buf_idx - lag + 1; int num2 = sLTP_buf_idx - lag + 2; int num3 = Inlines.silk_RSHIFT(Gain_Q16, 6); for (int j = 0; j < length; j++) { int a; if (signalType == 2) { a = 2; a = Inlines.silk_SMLAWB(a, sLTP_Q15[num2], b_Q14[b_Q14_ptr]); a = Inlines.silk_SMLAWB(a, sLTP_Q15[num2 - 1], b_Q14[b_Q14_ptr + 1]); a = Inlines.silk_SMLAWB(a, sLTP_Q15[num2 - 2], b_Q14[b_Q14_ptr + 2]); a = Inlines.silk_SMLAWB(a, sLTP_Q15[num2 - 3], b_Q14[b_Q14_ptr + 3]); a = Inlines.silk_SMLAWB(a, sLTP_Q15[num2 - 4], b_Q14[b_Q14_ptr + 4]); a = Inlines.silk_LSHIFT(a, 1); num2++; } else { a = 0; } int a2; if (lag > 0) { a2 = Inlines.silk_SMULWB(Inlines.silk_ADD32(sLTP_shp_Q14[num], sLTP_shp_Q14[num - 2]), HarmShapeFIRPacked_Q14); a2 = Inlines.silk_SMLAWT(a2, sLTP_shp_Q14[num - 1], HarmShapeFIRPacked_Q14); a2 = Inlines.silk_SUB_LSHIFT32(a, a2, 2); num++; } else { a2 = 0; } NSQ_del_dec_struct nSQ_del_dec_struct; for (int k = 0; k < nStatesDelayedDecision; k++) { nSQ_del_dec_struct = psDelDec[k]; int[] array2 = nSQ_del_dec_struct.sAR2_Q14; int num4 = 2 * k; int num5 = num4 + 1; nSQ_del_dec_struct.Seed = Inlines.silk_RAND(nSQ_del_dec_struct.Seed); int num6 = SilkConstants.NSQ_LPC_BUF_LENGTH - 1 + j; int a3 = Inlines.silk_RSHIFT(predictLPCOrder, 1); a3 = Inlines.silk_SMLAWB(a3, nSQ_del_dec_struct.sLPC_Q14[num6], a_Q12[0]); a3 = Inlines.silk_SMLAWB(a3, nSQ_del_dec_struct.sLPC_Q14[num6 - 1], a_Q12[1]); a3 = Inlines.silk_SMLAWB(a3, nSQ_del_dec_struct.sLPC_Q14[num6 - 2], a_Q12[2]); a3 = Inlines.silk_SMLAWB(a3, nSQ_del_dec_struct.sLPC_Q14[num6 - 3], a_Q12[3]); a3 = Inlines.silk_SMLAWB(a3, nSQ_del_dec_struct.sLPC_Q14[num6 - 4], a_Q12[4]); a3 = Inlines.silk_SMLAWB(a3, nSQ_del_dec_struct.sLPC_Q14[num6 - 5], a_Q12[5]); a3 = Inlines.silk_SMLAWB(a3, nSQ_del_dec_struct.sLPC_Q14[num6 - 6], a_Q12[6]); a3 = Inlines.silk_SMLAWB(a3, nSQ_del_dec_struct.sLPC_Q14[num6 - 7], a_Q12[7]); a3 = Inlines.silk_SMLAWB(a3, nSQ_del_dec_struct.sLPC_Q14[num6 - 8], a_Q12[8]); a3 = Inlines.silk_SMLAWB(a3, nSQ_del_dec_struct.sLPC_Q14[num6 - 9], a_Q12[9]); if (predictLPCOrder == 16) { a3 = Inlines.silk_SMLAWB(a3, nSQ_del_dec_struct.sLPC_Q14[num6 - 10], a_Q12[10]); a3 = Inlines.silk_SMLAWB(a3, nSQ_del_dec_struct.sLPC_Q14[num6 - 11], a_Q12[11]); a3 = Inlines.silk_SMLAWB(a3, nSQ_del_dec_struct.sLPC_Q14[num6 - 12], a_Q12[12]); a3 = Inlines.silk_SMLAWB(a3, nSQ_del_dec_struct.sLPC_Q14[num6 - 13], a_Q12[13]); a3 = Inlines.silk_SMLAWB(a3, nSQ_del_dec_struct.sLPC_Q14[num6 - 14], a_Q12[14]); a3 = Inlines.silk_SMLAWB(a3, nSQ_del_dec_struct.sLPC_Q14[num6 - 15], a_Q12[15]); } a3 = Inlines.silk_LSHIFT(a3, 4); int num7 = Inlines.silk_SMLAWB(nSQ_del_dec_struct.sLPC_Q14[num6], array2[0], warping_Q16); int num8 = Inlines.silk_SMLAWB(array2[0], array2[1] - num7, warping_Q16); array2[0] = num7; int a4 = Inlines.silk_RSHIFT(shapingLPCOrder, 1); a4 = Inlines.silk_SMLAWB(a4, num7, AR_shp_Q13[AR_shp_Q13_ptr]); for (int l = 2; l < shapingLPCOrder; l += 2) { num7 = Inlines.silk_SMLAWB(array2[l - 1], array2[l] - num8, warping_Q16); array2[l - 1] = num8; a4 = Inlines.silk_SMLAWB(a4, num8, AR_shp_Q13[AR_shp_Q13_ptr + l - 1]); num8 = Inlines.silk_SMLAWB(array2[l], array2[l + 1] - num7, warping_Q16); array2[l] = num7; a4 = Inlines.silk_SMLAWB(a4, num7, AR_shp_Q13[AR_shp_Q13_ptr + l]); } array2[shapingLPCOrder - 1] = num8; a4 = Inlines.silk_SMLAWB(a4, num8, AR_shp_Q13[AR_shp_Q13_ptr + shapingLPCOrder - 1]); a4 = Inlines.silk_LSHIFT(a4, 1); a4 = Inlines.silk_SMLAWB(a4, nSQ_del_dec_struct.LF_AR_Q14, Tilt_Q14); a4 = Inlines.silk_LSHIFT(a4, 2); int a5 = Inlines.silk_SMULWB(nSQ_del_dec_struct.Shape_Q14[smpl_buf_idx.Val], LF_shp_Q14); a5 = Inlines.silk_SMLAWT(a5, nSQ_del_dec_struct.LF_AR_Q14, LF_shp_Q14); a5 = Inlines.silk_LSHIFT(a5, 2); num8 = Inlines.silk_ADD32(a4, a5); num7 = Inlines.silk_ADD32(a2, a3); num8 = Inlines.silk_SUB32(num7, num8); num8 = Inlines.silk_RSHIFT_ROUND(num8, 4); int num9 = Inlines.silk_SUB32(x_Q10[j], num8); if (nSQ_del_dec_struct.Seed < 0) { num9 = -num9; } num9 = Inlines.silk_LIMIT_32(num9, -31744, 30720); int a6 = Inlines.silk_SUB32(num9, offset_Q10); int num10 = Inlines.silk_RSHIFT(a6, 10); int num11; int a7; int a8; if (num10 > 0) { a6 = Inlines.silk_SUB32(Inlines.silk_LSHIFT(num10, 10), 80); a6 = Inlines.silk_ADD32(a6, offset_Q10); num11 = Inlines.silk_ADD32(a6, 1024); a7 = Inlines.silk_SMULBB(a6, Lambda_Q10); a8 = Inlines.silk_SMULBB(num11, Lambda_Q10); } else { switch (num10) { case 0: a6 = offset_Q10; num11 = Inlines.silk_ADD32(a6, 944); a7 = Inlines.silk_SMULBB(a6, Lambda_Q10); a8 = Inlines.silk_SMULBB(num11, Lambda_Q10); break; case -1: num11 = offset_Q10; a6 = Inlines.silk_SUB32(num11, 944); a7 = Inlines.silk_SMULBB(-a6, Lambda_Q10); a8 = Inlines.silk_SMULBB(num11, Lambda_Q10); break; default: a6 = Inlines.silk_ADD32(Inlines.silk_LSHIFT(num10, 10), 80); a6 = Inlines.silk_ADD32(a6, offset_Q10); num11 = Inlines.silk_ADD32(a6, 1024); a7 = Inlines.silk_SMULBB(-a6, Lambda_Q10); a8 = Inlines.silk_SMULBB(-num11, Lambda_Q10); break; } } int num12 = Inlines.silk_SUB32(num9, a6); a7 = Inlines.silk_RSHIFT(Inlines.silk_SMLABB(a7, num12, num12), 10); num12 = Inlines.silk_SUB32(num9, num11); a8 = Inlines.silk_RSHIFT(Inlines.silk_SMLABB(a8, num12, num12), 10); if (a7 < a8) { array[num4].RD_Q10 = Inlines.silk_ADD32(nSQ_del_dec_struct.RD_Q10, a7); array[num5].RD_Q10 = Inlines.silk_ADD32(nSQ_del_dec_struct.RD_Q10, a8); array[num4].Q_Q10 = a6; array[num5].Q_Q10 = num11; } else { array[num4].RD_Q10 = Inlines.silk_ADD32(nSQ_del_dec_struct.RD_Q10, a8); array[num5].RD_Q10 = Inlines.silk_ADD32(nSQ_del_dec_struct.RD_Q10, a7); array[num4].Q_Q10 = num11; array[num5].Q_Q10 = a6; } int num13 = Inlines.silk_LSHIFT32(array[num4].Q_Q10, 4); if (nSQ_del_dec_struct.Seed < 0) { num13 = -num13; } int num14 = Inlines.silk_ADD32(num13, a); int num15 = Inlines.silk_ADD32(num14, a3); int num16 = Inlines.silk_SUB32(num15, a4); array[num4].sLTP_shp_Q14 = Inlines.silk_SUB32(num16, a5); array[num4].LF_AR_Q14 = num16; array[num4].LPC_exc_Q14 = num14; array[num4].xq_Q14 = num15; num13 = Inlines.silk_LSHIFT32(array[num5].Q_Q10, 4); if (nSQ_del_dec_struct.Seed < 0) { num13 = -num13; } num14 = Inlines.silk_ADD32(num13, a); num15 = Inlines.silk_ADD32(num14, a3); num16 = Inlines.silk_SUB32(num15, a4); array[num5].sLTP_shp_Q14 = Inlines.silk_SUB32(num16, a5); array[num5].LF_AR_Q14 = num16; array[num5].LPC_exc_Q14 = num14; array[num5].xq_Q14 = num15; } smpl_buf_idx.Val = (smpl_buf_idx.Val - 1) & 0x1F; int num17 = (smpl_buf_idx.Val + decisionDelay) & 0x1F; int rD_Q = array[0].RD_Q10; int num18 = 0; for (int k = 1; k < nStatesDelayedDecision; k++) { if (array[k * 2].RD_Q10 < rD_Q) { rD_Q = array[k * 2].RD_Q10; num18 = k; } } int num19 = psDelDec[num18].RandState[num17]; for (int k = 0; k < nStatesDelayedDecision; k++) { if (psDelDec[k].RandState[num17] != num19) { int num20 = k * 2; array[num20].RD_Q10 = Inlines.silk_ADD32(array[num20].RD_Q10, 134217727); array[num20 + 1].RD_Q10 = Inlines.silk_ADD32(array[num20 + 1].RD_Q10, 134217727); } } int rD_Q2 = array[0].RD_Q10; rD_Q = array[1].RD_Q10; int num21 = 0; int num22 = 0; for (int k = 1; k < nStatesDelayedDecision; k++) { int num23 = k * 2; if (array[num23].RD_Q10 > rD_Q2) { rD_Q2 = array[num23].RD_Q10; num21 = k; } if (array[num23 + 1].RD_Q10 < rD_Q) { rD_Q = array[num23 + 1].RD_Q10; num22 = k; } } if (rD_Q < rD_Q2) { psDelDec[num21].PartialCopyFrom(psDelDec[num22], j); array[num21 * 2] = array[num22 * 2 + 1]; } nSQ_del_dec_struct = psDelDec[num18]; if (subfr > 0 || j >= decisionDelay) { pulses[pulses_ptr + j - decisionDelay] = (sbyte)Inlines.silk_RSHIFT_ROUND(nSQ_del_dec_struct.Q_Q10[num17], 10); xq[xq_ptr + j - decisionDelay] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(nSQ_del_dec_struct.Xq_Q14[num17], delayedGain_Q10[num17]), 8)); sLTP_shp_Q14[sLTP_shp_buf_idx - decisionDelay] = nSQ_del_dec_struct.Shape_Q14[num17]; sLTP_Q15[sLTP_buf_idx - decisionDelay] = nSQ_del_dec_struct.Pred_Q15[num17]; } sLTP_shp_buf_idx++; sLTP_buf_idx++; for (int k = 0; k < nStatesDelayedDecision; k++) { nSQ_del_dec_struct = psDelDec[k]; int num4 = k * 2; nSQ_del_dec_struct.LF_AR_Q14 = array[num4].LF_AR_Q14; nSQ_del_dec_struct.sLPC_Q14[SilkConstants.NSQ_LPC_BUF_LENGTH + j] = array[num4].xq_Q14; nSQ_del_dec_struct.Xq_Q14[smpl_buf_idx.Val] = array[num4].xq_Q14; nSQ_del_dec_struct.Q_Q10[smpl_buf_idx.Val] = array[num4].Q_Q10; nSQ_del_dec_struct.Pred_Q15[smpl_buf_idx.Val] = Inlines.silk_LSHIFT32(array[num4].LPC_exc_Q14, 1); nSQ_del_dec_struct.Shape_Q14[smpl_buf_idx.Val] = array[num4].sLTP_shp_Q14; nSQ_del_dec_struct.Seed = Inlines.silk_ADD32_ovflw(nSQ_del_dec_struct.Seed, Inlines.silk_RSHIFT_ROUND(array[num4].Q_Q10, 10)); nSQ_del_dec_struct.RandState[smpl_buf_idx.Val] = nSQ_del_dec_struct.Seed; nSQ_del_dec_struct.RD_Q10 = array[num4].RD_Q10; } delayedGain_Q10[smpl_buf_idx.Val] = num3; } for (int k = 0; k < nStatesDelayedDecision; k++) { NSQ_del_dec_struct nSQ_del_dec_struct = psDelDec[k]; Buffer.BlockCopy(nSQ_del_dec_struct.sLPC_Q14, length * 4, nSQ_del_dec_struct.sLPC_Q14, 0, SilkConstants.NSQ_LPC_BUF_LENGTH * 4); } } private void silk_nsq_del_dec_scale_states(SilkChannelEncoder psEncC, NSQ_del_dec_struct[] psDelDec, int[] x_Q3, int x_Q3_ptr, int[] x_sc_Q10, short[] sLTP, int[] sLTP_Q15, int subfr, int nStatesDelayedDecision, int LTP_scale_Q14, int[] Gains_Q16, int[] pitchL, int signal_type, int decisionDelay) { int num = pitchL[subfr]; int num2 = Inlines.silk_INVERSE32_varQ(Inlines.silk_max(Gains_Q16[subfr], 1), 47); int num3 = ((Gains_Q16[subfr] == prev_gain_Q16) ? 65536 : Inlines.silk_DIV32_varQ(prev_gain_Q16, Gains_Q16[subfr], 16)); int b = Inlines.silk_RSHIFT_ROUND(num2, 8); for (int i = 0; i < psEncC.subfr_length; i++) { x_sc_Q10[i] = Inlines.silk_SMULWW(x_Q3[x_Q3_ptr + i], b); } prev_gain_Q16 = Gains_Q16[subfr]; if (rewhite_flag != 0) { if (subfr == 0) { num2 = Inlines.silk_LSHIFT(Inlines.silk_SMULWB(num2, LTP_scale_Q14), 2); } for (int i = sLTP_buf_idx - num - 2; i < sLTP_buf_idx; i++) { sLTP_Q15[i] = Inlines.silk_SMULWB(num2, sLTP[i]); } } if (num3 == 65536) { return; } for (int i = sLTP_shp_buf_idx - psEncC.ltp_mem_length; i < sLTP_shp_buf_idx; i++) { sLTP_shp_Q14[i] = Inlines.silk_SMULWW(num3, sLTP_shp_Q14[i]); } if (signal_type == 2 && rewhite_flag == 0) { for (int i = sLTP_buf_idx - num - 2; i < sLTP_buf_idx - decisionDelay; i++) { sLTP_Q15[i] = Inlines.silk_SMULWW(num3, sLTP_Q15[i]); } } for (int j = 0; j < nStatesDelayedDecision; j++) { NSQ_del_dec_struct nSQ_del_dec_struct = psDelDec[j]; nSQ_del_dec_struct.LF_AR_Q14 = Inlines.silk_SMULWW(num3, nSQ_del_dec_struct.LF_AR_Q14); for (int i = 0; i < SilkConstants.NSQ_LPC_BUF_LENGTH; i++) { nSQ_del_dec_struct.sLPC_Q14[i] = Inlines.silk_SMULWW(num3, nSQ_del_dec_struct.sLPC_Q14[i]); } for (int i = 0; i < psEncC.shapingLPCOrder; i++) { nSQ_del_dec_struct.sAR2_Q14[i] = Inlines.silk_SMULWW(num3, nSQ_del_dec_struct.sAR2_Q14[i]); } for (int i = 0; i < 32; i++) { nSQ_del_dec_struct.Pred_Q15[i] = Inlines.silk_SMULWW(num3, nSQ_del_dec_struct.Pred_Q15[i]); nSQ_del_dec_struct.Shape_Q14[i] = Inlines.silk_SMULWW(num3, nSQ_del_dec_struct.Shape_Q14[i]); } } } } internal class SilkPrefilterState { internal readonly short[] sLTP_shp = new short[512]; internal readonly int[] sAR_shp = new int[17]; internal int sLTP_shp_buf_idx; internal int sLF_AR_shp_Q12; internal int sLF_MA_shp_Q12; internal int sHarmHP_Q2; internal int rand_seed; internal int lagPrev; internal SilkPrefilterState() { } internal void Reset() { Arrays.MemSetShort(sLTP_shp, 0, 512); Arrays.MemSetInt(sAR_shp, 0, 17); sLTP_shp_buf_idx = 0; sLF_AR_shp_Q12 = 0; sLF_MA_shp_Q12 = 0; sHarmHP_Q2 = 0; rand_seed = 0; lagPrev = 0; } } internal class SilkResamplerState { internal readonly int[] sIIR = new int[6]; internal readonly int[] sFIR_i32 = new int[36]; internal readonly short[] sFIR_i16 = new short[36]; internal readonly short[] delayBuf = new short[48]; internal int resampler_function; internal int batchSize; internal int invRatio_Q16; internal int FIR_Order; internal int FIR_Fracs; internal int Fs_in_kHz; internal int Fs_out_kHz; internal int inputDelay; internal short[] Coefs; internal void Reset() { Arrays.MemSetInt(sIIR, 0, 6); Arrays.MemSetInt(sFIR_i32, 0, 36); Arrays.MemSetShort(sFIR_i16, 0, 36); Arrays.MemSetShort(delayBuf, 0, 48); resampler_function = 0; batchSize = 0; invRatio_Q16 = 0; FIR_Order = 0; FIR_Fracs = 0; Fs_in_kHz = 0; Fs_out_kHz = 0; inputDelay = 0; Coefs = null; } internal void Assign(SilkResamplerState other) { resampler_function = other.resampler_function; batchSize = other.batchSize; invRatio_Q16 = other.invRatio_Q16; FIR_Order = other.FIR_Order; FIR_Fracs = other.FIR_Fracs; Fs_in_kHz = other.Fs_in_kHz; Fs_out_kHz = other.Fs_out_kHz; inputDelay = other.inputDelay; Coefs = other.Coefs; Arrays.MemCopy(other.sIIR, 0, sIIR, 0, 6); Arrays.MemCopy(other.sFIR_i32, 0, sFIR_i32, 0, 36); Arrays.MemCopy(other.sFIR_i16, 0, sFIR_i16, 0, 36); Arrays.MemCopy(other.delayBuf, 0, delayBuf, 0, 48); } } internal class SilkShapeState { internal sbyte LastGainIndex; internal int HarmBoost_smth_Q16; internal int HarmShapeGain_smth_Q16; internal int Tilt_smth_Q16; internal void Reset() { LastGainIndex = 0; HarmBoost_smth_Q16 = 0; HarmShapeGain_smth_Q16 = 0; Tilt_smth_Q16 = 0; } } internal class SilkVADState { internal readonly int[] AnaState = new int[2]; internal readonly int[] AnaState1 = new int[2]; internal readonly int[] AnaState2 = new int[2]; internal readonly int[] XnrgSubfr = new int[4]; internal readonly int[] NrgRatioSmth_Q8 = new int[4]; internal short HPstate; internal readonly int[] NL = new int[4]; internal readonly int[] inv_NL = new int[4]; internal readonly int[] NoiseLevelBias = new int[4]; internal int counter; internal void Reset() { Arrays.MemSetInt(AnaState, 0, 2); Arrays.MemSetInt(AnaState1, 0, 2); Arrays.MemSetInt(AnaState2, 0, 2); Arrays.MemSetInt(XnrgSubfr, 0, 4); Arrays.MemSetInt(NrgRatioSmth_Q8, 0, 4); HPstate = 0; Arrays.MemSetInt(NL, 0, 4); Arrays.MemSetInt(inv_NL, 0, 4); Arrays.MemSetInt(NoiseLevelBias, 0, 4); counter = 0; } } internal class StereoDecodeState { internal readonly short[] pred_prev_Q13 = new short[2]; internal readonly short[] sMid = new short[2]; internal readonly short[] sSide = new short[2]; internal void Reset() { Arrays.MemSetShort(pred_prev_Q13, 0, 2); Arrays.MemSetShort(sMid, 0, 2); Arrays.MemSetShort(sSide, 0, 2); } } internal class StereoEncodeState { internal readonly short[] pred_prev_Q13 = new short[2]; internal readonly short[] sMid = new short[2]; internal readonly short[] sSide = new short[2]; internal readonly int[] mid_side_amp_Q0 = new int[4]; internal short smth_width_Q14; internal short width_prev_Q14; internal short silent_side_len; internal readonly sbyte[][][] predIx = Arrays.InitThreeDimensionalArray(3, 2, 3); internal readonly sbyte[] mid_only_flags = new sbyte[3]; internal void Reset() { Arrays.MemSetShort(pred_prev_Q13, 0, 2); Arrays.MemSetShort(sMid, 0, 2); Arrays.MemSetShort(sSide, 0, 2); Arrays.MemSetInt(mid_side_amp_Q0, 0, 4); smth_width_Q14 = 0; width_prev_Q14 = 0; silent_side_len = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 2; j++) { Arrays.MemSetSbyte(predIx[i][j], 0, 3); } } Arrays.MemSetSbyte(mid_only_flags, 0, 3); } } internal class TOCStruct { internal int VADFlag; internal readonly int[] VADFlags = new int[3]; internal int inbandFECFlag; internal void Reset() { VADFlag = 0; Arrays.MemSetInt(VADFlags, 0, 3); inbandFECFlag = 0; } } } namespace Concentus.Silk.Enums { internal static class DecoderAPIFlag { internal const int FLAG_DECODE_NORMAL = 0; internal const int FLAG_PACKET_LOST = 1; internal const int FLAG_DECODE_LBRR = 2; } internal static class SilkError { internal static int SILK_NO_ERROR = 0; internal static int SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES = -101; internal static int SILK_ENC_FS_NOT_SUPPORTED = -102; internal static int SILK_ENC_PACKET_SIZE_NOT_SUPPORTED = -103; internal static int SILK_ENC_PAYLOAD_BUF_TOO_SHORT = -104; internal static int SILK_ENC_INVALID_LOSS_RATE = -105; internal static int SILK_ENC_INVALID_COMPLEXITY_SETTING = -106; internal static int SILK_ENC_INVALID_INBAND_FEC_SETTING = -107; internal static int SILK_ENC_INVALID_DTX_SETTING = -108; internal static int SILK_ENC_INVALID_CBR_SETTING = -109; internal static int SILK_ENC_INTERNAL_ERROR = -110; internal static int SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR = -111; internal static int SILK_DEC_INVALID_SAMPLING_FREQUENCY = -200; internal static int SILK_DEC_PAYLOAD_TOO_LARGE = -201; internal static int SILK_DEC_PAYLOAD_ERROR = -202; internal static int SILK_DEC_INVALID_FRAME_SIZE = -203; } } namespace Concentus.Structs { internal class ChannelLayout { internal int nb_channels; internal int nb_streams; internal int nb_coupled_streams; internal readonly byte[] mapping = new byte[256]; internal void Reset() { nb_channels = 0; nb_streams = 0; nb_coupled_streams = 0; mapping.AsSpan().Clear(); } } internal class MLP { internal int layers; internal int[] topo; internal float[] weights; } public class OpusDecoder : IOpusDecoder, IDisposable { internal int channels; internal int Fs; internal readonly DecControlState DecControl = new DecControlState(); internal int decode_gain; internal int stream_channels; internal OpusBandwidth bandwidth; internal OpusMode mode; internal OpusMode prev_mode; internal int frame_size; internal int prev_redundancy; internal int last_packet_duration; internal uint rangeFinal; internal SilkDecoder SilkDecoder = new SilkDecoder(); internal CeltDecoder Celt_Decoder = new CeltDecoder(); private static readonly byte[] SILENCE = new byte[2] { 255, 255 }; public OpusBandwidth Bandwidth => bandwidth; public uint FinalRange => rangeFinal; public int SampleRate => Fs; public int NumChannels => channels; public int Pitch { get { if (prev_mode == OpusMode.MODE_CELT_ONLY) { return Celt_Decoder.GetPitch(); } return DecControl.prevPitchLag; } } public int Gain { get { return decode_gain; } set { if (value < -32768 || value > 32767) { throw new ArgumentException("Gain must be within the range of a signed int16"); } decode_gain = value; } } public int LastPacketDuration => last_packet_duration; internal OpusDecoder() { } internal void Reset() { channels = 0; Fs = 0; DecControl.Reset(); decode_gain = 0; PartialReset(); } internal void PartialReset() { stream_channels = 0; bandwidth = (OpusBandwidth)0; mode = (OpusMode)0; prev_mode = (OpusMode)0; frame_size = 0; prev_redundancy = 0; last_packet_duration = 0; rangeFinal = 0u; } [Obsolete("Use OpusCodecFactory methods which can give you native code if supported by your platform")] public OpusDecoder(int Fs, int channels) { if (Fs != 48000 && Fs != 24000 && Fs != 16000 && Fs != 12000 && Fs != 8000) { throw new ArgumentException("Sample rate is invalid (must be 8/12/16/24/48 Khz)"); } if (channels != 1 && channels != 2) { throw new ArgumentException("Number of channels must be 1 or 2"); } int num = opus_decoder_init(Fs, channels); switch (num) { case -1: throw new ArgumentException("OPUS_BAD_ARG when creating decoder"); default: throw new OpusException("Error while initializing decoder: " + CodecHelpers.opus_strerror(num), num); case 0: break; } } internal int opus_decoder_init(int Fs, int channels) { if ((Fs != 48000 && Fs != 24000 && Fs != 16000 && Fs != 12000 && Fs != 8000) || (channels != 1 && channels != 2)) { return -1; } Reset(); SilkDecoder silkDecoder = SilkDecoder; CeltDecoder celt_Decoder = Celt_Decoder; stream_channels = (this.channels = channels); this.Fs = Fs; DecControl.API_sampleRate = this.Fs; DecControl.nChannelsAPI = this.channels; if (DecodeAPI.silk_InitDecoder(silkDecoder) != 0) { return -3; } if (celt_Decoder.celt_decoder_init(Fs, channels) != 0) { return -3; } celt_Decoder.SetSignalling(0); prev_mode = (OpusMode)0; frame_size = Fs / 400; return 0; } internal int opus_decode_frame(ReadOnlySpan data, int data_ptr, int len, Span pcm, int pcm_ptr, int frame_size, int decode_fec) { int num = 0; EntropyCoder entropyCoder = new EntropyCoder(); short[] array = null; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; uint num6 = 0u; SilkDecoder silkDecoder = SilkDecoder; CeltDecoder celt_Decoder = Celt_Decoder; int num7 = Fs / 50; int num8 = num7 >> 1; int num9 = num8 >> 1; int num10 = num9 >> 1; if (frame_size < num10) { return -2; } frame_size = Inlines.IMIN(frame_size, Fs / 25 * 3); if (len <= 1) { data = null; frame_size = Inlines.IMIN(frame_size, this.frame_size); } int num11; OpusMode opusMode; if (!data.IsEmpty) { num11 = this.frame_size; opusMode = mode; entropyCoder.dec_init(data.Slice(data_ptr), (uint)len); } else { num11 = frame_size; opusMode = prev_mode; if (opusMode == (OpusMode)0) { for (int i = pcm_ptr; i < pcm_ptr + num11 * channels; i++) { pcm[i] = 0; } return num11; } if (num11 > num7) { do { int num12 = opus_decode_frame(null, 0, 0, pcm, pcm_ptr, Inlines.IMIN(num11, num7), 0); if (num12 < 0) { return num12; } pcm_ptr += num12 * channels; num11 -= num12; } while (num11 > 0); return frame_size; } if (num11 < num7) { if (num11 > num8) { num11 = num8; } else if (opusMode != OpusMode.MODE_SILK_ONLY && num11 > num9 && num11 < num8) { num11 = num9; } } } int num13 = ((opusMode != OpusMode.MODE_CELT_ONLY && frame_size >= num8) ? 1 : 0); int num14 = 0; int num15 = 0; if (!data.IsEmpty && prev_mode > (OpusMode)0 && ((opusMode == OpusMode.MODE_CELT_ONLY && prev_mode != OpusMode.MODE_CELT_ONLY && prev_redundancy == 0) || (opusMode != OpusMode.MODE_CELT_ONLY && prev_mode == OpusMode.MODE_CELT_ONLY))) { num2 = 1; if (opusMode == OpusMode.MODE_CELT_ONLY) { num15 = num9 * channels; } else { num14 = num9 * channels; } } short[] array2 = new short[num15]; if (num2 != 0 && opusMode == OpusMode.MODE_CELT_ONLY) { array = array2; opus_decode_frame(null, 0, 0, array, 0, Inlines.IMIN(num9, num11), 0); } if (num11 > frame_size) { return -1; } frame_size = num11; short[] array3 = new short[(opusMode != OpusMode.MODE_CELT_ONLY && num13 == 0) ? (Inlines.IMAX(num8, frame_size) * channels) : 0]; if (opusMode != OpusMode.MODE_CELT_ONLY) { int num16 = 0; Span span; if (num13 != 0) { span = pcm; num16 = pcm_ptr; } else { span = array3; num16 = 0; } if (prev_mode == OpusMode.MODE_CELT_ONLY) { DecodeAPI.silk_InitDecoder(silkDecoder); } DecControl.payloadSize_ms = Inlines.IMAX(10, 1000 * num11 / Fs); if (!data.IsEmpty) { DecControl.nChannelsInternal = stream_channels; if (opusMode == OpusMode.MODE_SILK_ONLY) { if (bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) { DecControl.internalSampleRate = 8000; } else if (bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) { DecControl.internalSampleRate = 12000; } else if (bandwidth == OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND) { DecControl.internalSampleRate = 16000; } else { DecControl.internalSampleRate = 16000; } } else { DecControl.internalSampleRate = 16000; } } int num17 = (data.IsEmpty ? 1 : (2 * decode_fec)); int num18 = 0; do { int newPacketFlag = ((num18 == 0) ? 1 : 0); if (DecodeAPI.silk_Decode(silkDecoder, DecControl, data.Slice(data_ptr), num17, newPacketFlag, entropyCoder, span, num16, out var nSamplesOut) != 0) { if (num17 == 0) { return -3; } nSamplesOut = frame_size; Arrays.MemSetWithOffset(span, 0, num16, frame_size * channels); } num16 += nSamplesOut * channels; num18 += nSamplesOut; } while (num18 < frame_size); } int startBand = 0; if (decode_fec == 0 && opusMode != OpusMode.MODE_CELT_ONLY && !data.IsEmpty && entropyCoder.tell() + 17 + 20 * ((mode == OpusMode.MODE_HYBRID) ? 1 : 0) <= 8 * len) { num3 = ((opusMode != OpusMode.MODE_HYBRID) ? 1 : entropyCoder.dec_bit_logp(data.Slice(data_ptr), 12u)); if (num3 != 0) { num5 = entropyCoder.dec_bit_logp(data.Slice(data_ptr), 1u); num4 = ((opusMode == OpusMode.MODE_HYBRID) ? ((int)(entropyCoder.dec_uint(data.Slice(data_ptr), 256u) + 2)) : (len - (entropyCoder.tell() + 7 >> 3))); len -= num4; if (len * 8 < entropyCoder.tell()) { len = 0; num4 = 0; num3 = 0; } entropyCoder.storage = (uint)(entropyCoder.storage - num4); } } if (opusMode != OpusMode.MODE_CELT_ONLY) { startBand = 17; } int endBand = 21; switch (bandwidth) { case OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND: endBand = 13; break; case OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND: case OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND: endBand = 17; break; case OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND: endBand = 19; break; case OpusBandwidth.OPUS_BANDWIDTH_FULLBAND: endBand = 21; break; } celt_Decoder.SetEndBand(endBand); celt_Decoder.SetChannels(stream_channels); if (num3 != 0) { num2 = 0; num14 = 0; } short[] array4 = new short[num14]; if (num2 != 0 && opusMode != OpusMode.MODE_CELT_ONLY) { array = array4; opus_decode_frame(null, 0, 0, array, 0, Inlines.IMIN(num9, num11), 0); } short[] array5 = new short[(num3 != 0) ? (num9 * channels) : 0]; if (num3 != 0 && num5 != 0) { celt_Decoder.SetStartBand(0); celt_Decoder.celt_decode_with_ec(data, data_ptr + len, num4, array5, 0, num9, null, 0); num6 = celt_Decoder.GetFinalRange(); } celt_Decoder.SetStartBand(startBand); if (opusMode != OpusMode.MODE_SILK_ONLY) { int num19 = Inlines.IMIN(num7, frame_size); if (opusMode != prev_mode && prev_mode > (OpusMode)0 && prev_redundancy == 0) { celt_Decoder.ResetState(); } num = celt_Decoder.celt_decode_with_ec((decode_fec != 0) ? ((ReadOnlySpan)null) : data, data_ptr, len, pcm, pcm_ptr, num19, entropyCoder, num13); } else { if (num13 == 0) { for (int i = pcm_ptr; i < frame_size * channels + pcm_ptr; i++) { pcm[i] = 0; } } if (prev_mode == OpusMode.MODE_HYBRID && (num3 == 0 || num5 == 0 || prev_redundancy == 0)) { celt_Decoder.SetStartBand(0); celt_Decoder.celt_decode_with_ec(SILENCE, 0, 2, pcm, pcm_ptr, num10, null, num13); } } if (opusMode != OpusMode.MODE_CELT_ONLY && num13 == 0) { for (int i = 0; i < frame_size * channels; i++) { pcm[pcm_ptr + i] = Inlines.SAT16(Inlines.ADD32(pcm[pcm_ptr + i], array3[i])); } } int[] window = celt_Decoder.GetMode().window; if (num3 != 0 && num5 == 0) { celt_Decoder.ResetState(); celt_Decoder.SetStartBand(0); celt_Decoder.celt_decode_with_ec(data, data_ptr + len, num4, array5, 0, num9, null, 0); num6 = celt_Decoder.GetFinalRange(); CodecHelpers.smooth_fade(pcm, pcm_ptr + channels * (frame_size - num10), array5, channels * num10, pcm, pcm_ptr + channels * (frame_size - num10), num10, channels, window, Fs); } if (num3 != 0 && num5 != 0) { for (int j = 0; j < channels; j++) { for (int i = 0; i < num10; i++) { pcm[channels * i + j + pcm_ptr] = array5[channels * i + j]; } } CodecHelpers.smooth_fade(array5, channels * num10, pcm, pcm_ptr + channels * num10, pcm, pcm_ptr + channels * num10, num10, channels, window, Fs); } if (num2 != 0) { if (num11 >= num9) { for (int i = 0; i < channels * num10; i++) { pcm[i] = array[i]; } CodecHelpers.smooth_fade(array, channels * num10, pcm, pcm_ptr + channels * num10, pcm, pcm_ptr + channels * num10, num10, channels, window, Fs); } else { CodecHelpers.smooth_fade(array, 0, pcm, pcm_ptr, pcm, pcm_ptr, num10, channels, window, Fs); } } if (decode_gain != 0) { int b = Inlines.celt_exp2(Inlines.MULT16_16_P15(21771, decode_gain)); for (int i = pcm_ptr; i < pcm_ptr + frame_size * channels; i++) { int x = Inlines.MULT16_32_P16(pcm[i], b); pcm[i] = (short)Inlines.SATURATE(x, 32767); } } if (len <= 1) { rangeFinal = 0u; } else { rangeFinal = entropyCoder.rng ^ num6; } prev_mode = opusMode; prev_redundancy = ((num3 != 0 && num5 == 0) ? 1 : 0); if (num >= 0) { return num11; } return num; } internal int opus_decode_native(ReadOnlySpan data, int data_ptr, int len, Span pcm_out, int pcm_out_ptr, int frame_size, int decode_fec, int self_delimited, out int packet_offset, int soft_clip) { packet_offset = 0; short[] array = new short[48]; if (decode_fec < 0 || decode_fec > 1) { return -1; } if ((decode_fec != 0 || len == 0 || data.IsEmpty) && frame_size % (Fs / 400) != 0) { return -1; } if (len == 0 || data.IsEmpty) { int num = 0; do { int num2 = opus_decode_frame(null, 0, 0, pcm_out, pcm_out_ptr + num * channels, frame_size - num, 0); if (num2 < 0) { return num2; } num += num2; } while (num < frame_size); last_packet_duration = num; return num; } if (len < 0) { return -1; } OpusMode encoderMode = OpusPacketInfo.GetEncoderMode(data.Slice(data_ptr)); OpusBandwidth opusBandwidth = OpusPacketInfo.GetBandwidth(data.Slice(data_ptr)); int numSamplesPerFrame = OpusPacketInfo.GetNumSamplesPerFrame(data.Slice(data_ptr), Fs); int numEncodedChannels = OpusPacketInfo.GetNumEncodedChannels(data.Slice(data_ptr)); byte out_toc; int payload_offset; int num3 = OpusPacketInfo.opus_packet_parse_impl(data, data_ptr, len, self_delimited, out out_toc, null, null, 0, array, 0, out payload_offset, out packet_offset); if (num3 < 0) { return num3; } data_ptr += payload_offset; if (decode_fec != 0) { int packet_offset2; if (frame_size < numSamplesPerFrame || encoderMode == OpusMode.MODE_CELT_ONLY || mode == OpusMode.MODE_CELT_ONLY) { return opus_decode_native(null, 0, 0, pcm_out, pcm_out_ptr, frame_size, 0, 0, out packet_offset2, soft_clip); } int num4 = last_packet_duration; int num5; if (frame_size - numSamplesPerFrame != 0) { num5 = opus_decode_native(null, 0, 0, pcm_out, pcm_out_ptr, frame_size - numSamplesPerFrame, 0, 0, out packet_offset2, soft_clip); if (num5 < 0) { last_packet_duration = num4; return num5; } } mode = encoderMode; bandwidth = opusBandwidth; this.frame_size = numSamplesPerFrame; stream_channels = numEncodedChannels; num5 = opus_decode_frame(data, data_ptr, array[0], pcm_out, pcm_out_ptr + channels * (frame_size - numSamplesPerFrame), numSamplesPerFrame, 1); if (num5 < 0) { return num5; } last_packet_duration = frame_size; return frame_size; } if (num3 * numSamplesPerFrame > frame_size) { return -2; } mode = encoderMode; bandwidth = opusBandwidth; this.frame_size = numSamplesPerFrame; stream_channels = numEncodedChannels; int num6 = 0; for (int i = 0; i < num3; i++) { int num7 = opus_decode_frame(data, data_ptr, array[i], pcm_out, pcm_out_ptr + num6 * channels, frame_size - num6, 0); if (num7 < 0) { return num7; } data_ptr += array[i]; num6 += num7; } last_packet_duration = num6; return num6; } [Obsolete("Use Span<> overrides if possible")] public int Decode(byte[] in_data, int in_data_offset, int len, short[] out_pcm, int out_pcm_offset, int frame_size, bool decode_fec = false) { if (in_data == null) { return Decode(ReadOnlySpan.Empty, out_pcm.AsSpan(out_pcm_offset), frame_size, decode_fec); } return Decode(in_data.AsSpan(in_data_offset, len), out_pcm.AsSpan(out_pcm_offset), frame_size, decode_fec); } public int Decode(ReadOnlySpan in_data, Span out_pcm, int frame_size, bool decode_fec = false) { if (frame_size <= 0) { throw new ArgumentException("Frame size must be > 0"); } try { int packet_offset; int num = opus_decode_native(in_data, 0, in_data.Length, out_pcm, 0, frame_size, decode_fec ? 1 : 0, 0, out packet_offset, 0); if (num < 0) { if (num == -1) { throw new ArgumentException("OPUS_BAD_ARG while decoding"); } throw new OpusException("An error occurred during decoding: " + CodecHelpers.opus_strerror(num), num); } return num; } catch (ArgumentException ex) { throw new OpusException("public error during decoding: " + ex.Message, -1); } } [Obsolete("Use Span<> overrides if possible")] public int Decode(byte[] in_data, int in_data_offset, int len, float[] out_pcm, int out_pcm_offset, int frame_size, bool decode_fec = false) { if (in_data == null) { return Decode(ReadOnlySpan.Empty, out_pcm.AsSpan(out_pcm_offset), frame_size, decode_fec); } return Decode(in_data.AsSpan(in_data_offset, len), out_pcm.AsSpan(out_pcm_offset), frame_size, decode_fec); } public int Decode(ReadOnlySpan in_data, Span out_pcm, int frame_size, bool decode_fec = false) { if (frame_size <= 0) { throw new ArgumentException("Frame size must be > 0"); } if (!in_data.IsEmpty && in_data.Length > 0 && !decode_fec) { int numSamples = OpusPacketInfo.GetNumSamples(in_data, Fs); if (numSamples <= 0) { throw new OpusException("An invalid packet was provided (unable to parse # of samples)", -4); } frame_size = Inlines.IMIN(frame_size, numSamples); } short[] array = new short[frame_size * channels]; try { int packet_offset; int num = opus_decode_native(in_data, 0, in_data.Length, array, 0, frame_size, decode_fec ? 1 : 0, 0, out packet_offset, 0); if (num < 0) { if (num == -1) { throw new ArgumentException("OPUS_BAD_ARG when decoding"); } throw new OpusException("An error occurred during decoding: " + CodecHelpers.opus_strerror(num), num); } if (num > 0) { for (int i = 0; i < num * channels; i++) { out_pcm[i] = 3.0517578E-05f * (float)array[i]; } } return num; } catch (ArgumentException ex) { throw new OpusException("public error during decoding: " + ex.Message, -1); } } public void ResetState() { PartialReset(); Celt_Decoder.ResetState(); DecodeAPI.silk_InitDecoder(SilkDecoder); stream_channels = channels; frame_size = Fs / 400; } public string GetVersionString() { return CodecHelpers.GetVersionString(); } public void Dispose() { } } public class OpusEncoder : IOpusEncoder, IDisposable { internal readonly EncControlState silk_mode = new EncControlState(); internal OpusApplication application; internal int channels; internal int delay_compensation; internal int force_channels; internal OpusSignal signal_type; internal OpusBandwidth user_bandwidth; internal OpusBandwidth max_bandwidth; internal OpusMode user_forced_mode; internal int voice_ratio; internal int Fs; internal int use_vbr; internal int vbr_constraint; internal OpusFramesize variable_duration; internal int bitrate_bps; internal int user_bitrate_bps; internal int lsb_depth; internal int encoder_buffer; internal int lfe; internal readonly TonalityAnalysisState analysis = new TonalityAnalysisState(); internal int stream_channels; internal short hybrid_stereo_width_Q14; internal int variable_HP_smth2_Q15; internal int prev_HB_gain; internal readonly int[] hp_mem = new int[4]; internal OpusMode mode; internal OpusMode prev_mode; internal int prev_channels; internal int prev_framesize; internal OpusBandwidth bandwidth; internal int silk_bw_switch; internal int first; internal int[] energy_masking; internal readonly StereoWidthState width_mem = new StereoWidthState(); internal readonly short[] delay_buffer = new short[960]; internal OpusBandwidth detected_bandwidth; internal uint rangeFinal; private int? _vqLevel; internal readonly SilkEncoder SilkEncoder = new SilkEncoder(); internal readonly CeltEncoder Celt_Encoder = new CeltEncoder(); private static readonly int[][] vqTable = new int[11][] { new int[2] { 7000, 16000 }, new int[2] { 10000, 24000 }, new int[2] { 13000, 32000 }, new int[2] { 17000, 48000 }, new int[2] { 20000, 64000 }, new int[2] { 24000, 80000 }, new int[2] { 28000, 96000 }, new int[2] { 32000, 112000 }, new int[2] { 38000, 128000 }, new int[2] { 48000, 192000 }, new int[2] { 64000, 256000 } }; public OpusApplication Application { get { return application; } set { if (first == 0 && application != value) { throw new ArgumentException("Application cannot be changed after encoding has started"); } application = value; } } public int Bitrate { get { return user_bitrate_to_bitrate(user_bitrate_bps, prev_framesize, 1276); } set { if (ConstantQuality.HasValue) { throw new ArgumentException("Bitrate is read-only while the ConstantQuality parameter is set"); } if (value != -1000 && value != -1) { if (value <= 0) { throw new ArgumentException("Bitrate must be positive"); } if (value <= 500) { value = 500; } else if (value > 300000 * channels) { value = 300000 * channels; } } user_bitrate_bps = value; } } public int ForceChannels { get { return force_channels; } set { if ((value < 1 || value > channels) && value != -1000) { throw new ArgumentException("Force channels must be <= num. of channels"); } force_channels = value; } } public OpusBandwidth MaxBandwidth { get { return max_bandwidth; } set { max_bandwidth = value; if (max_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) { silk_mode.maxInternalSampleRate = 8000; } else if (max_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) { silk_mode.maxInternalSampleRate = 12000; } else { silk_mode.maxInternalSampleRate = 16000; } } } public OpusBandwidth Bandwidth { get { return bandwidth; } set { user_bandwidth = value; if (user_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) { silk_mode.maxInternalSampleRate = 8000; } else if (user_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) { silk_mode.maxInternalSampleRate = 12000; } else { silk_mode.maxInternalSampleRate = 16000; } } } public bool UseDTX { get { return silk_mode.useDTX != 0; } set { silk_mode.useDTX = (value ? 1 : 0); } } public int Complexity { get { return silk_mode.complexity; } set { if (value < 0 || value > 10) { throw new ArgumentException("Complexity must be between 0 and 10"); } silk_mode.complexity = value; Celt_Encoder.SetComplexity(value); } } public bool UseInbandFEC { get { return silk_mode.useInBandFEC != 0; } set { silk_mode.useInBandFEC = (value ? 1 : 0); } } public int PacketLossPercent { get { return silk_mode.packetLossPercentage; } set { if (value < 0 || value > 100) { throw new ArgumentException("Packet loss must be between 0 and 100"); } silk_mode.packetLossPercentage = value; Celt_Encoder.SetPacketLossPercent(value); } } public bool UseVBR { get { return use_vbr != 0; } set { use_vbr = (value ? 1 : 0); silk_mode.useCBR = ((!value) ? 1 : 0); } } public bool UseConstrainedVBR { get { return vbr_constraint != 0; } set { vbr_constraint = (value ? 1 : 0); } } public OpusSignal SignalType { get { return signal_type; } set { signal_type = value; } } public int Lookahead { get { int num = Fs / 400; if (application != OpusApplication.OPUS_APPLICATION_RESTRICTED_LOWDELAY) { num += delay_compensation; } return num; } } public int SampleRate => Fs; public int NumChannels => channels; public uint FinalRange => rangeFinal; public int LSBDepth { get { return lsb_depth; } set { if (value < 8 || value > 24) { throw new ArgumentException("LSB depth must be between 8 and 24"); } lsb_depth = value; } } public OpusFramesize ExpertFrameDuration { get { return variable_duration; } set { variable_duration = value; Celt_Encoder.SetExpertFrameDuration(value); } } public OpusMode ForceMode { get { return user_forced_mode; } set { user_forced_mode = value; } } public bool IsLFE { get { return lfe != 0; } set { lfe = (value ? 1 : 0); Celt_Encoder.SetLFE(value ? 1 : 0); } } public bool PredictionDisabled { get { return silk_mode.reducedDependency != 0; } set { silk_mode.reducedDependency = (value ? 1 : 0); } } public bool EnableAnalysis { get { return analysis.enabled; } set { if (!value && _vqLevel.HasValue) { throw new ArgumentException("You cannot disable analysis while also specifying a ConstantQuality parameter"); } if (value && Fs != 48000) { throw new ArgumentException("EnableAnalysis only works if the encoder is in 48000Khz mode"); } analysis.enabled = value; } } public int? ConstantQuality { get { return _vqLevel; } set { if (value.HasValue && (value.Value < 0 || value.Value > 10)) { throw new ArgumentException("Constant quality VBR level must be either null (disabled) or between 0 and 10, inclusive."); } if (value.HasValue && Fs != 48000) { throw new ArgumentException("ConstantQuality only works if the encoder is in 48000Khz mode"); } EnableAnalysis = true; _vqLevel = value; } } public float MusicProbability => analysis.music_prob; internal OpusEncoder() { } internal void Reset() { silk_mode.Reset(); application = OpusApplication.OPUS_APPLICATION_UNIMPLEMENTED; channels = 0; delay_compensation = 0; force_channels = 0; signal_type = (OpusSignal)0; user_bandwidth = (OpusBandwidth)0; max_bandwidth = (OpusBandwidth)0; user_forced_mode = (OpusMode)0; voice_ratio = 0; Fs = 0; use_vbr = 0; vbr_constraint = 0; variable_duration = (OpusFramesize)0; bitrate_bps = 0; user_bitrate_bps = 0; lsb_depth = 0; encoder_buffer = 0; lfe = 0; analysis.Reset(); PartialReset(); } internal void PartialReset() { stream_channels = 0; hybrid_stereo_width_Q14 = 0; variable_HP_smth2_Q15 = 0; prev_HB_gain = 0; Arrays.MemSetInt(hp_mem, 0, 4); mode = (OpusMode)0; prev_mode = (OpusMode)0; prev_channels = 0; prev_framesize = 0; bandwidth = (OpusBandwidth)0; silk_bw_switch = 0; first = 0; energy_masking = null; width_mem.Reset(); Arrays.MemSetShort(delay_buffer, 0, 960); detected_bandwidth = (OpusBandwidth)0; rangeFinal = 0u; } public void ResetState() { EncControlState encStatus = new EncControlState(); analysis.Reset(); PartialReset(); Celt_Encoder.ResetState(); EncodeAPI.silk_InitEncoder(SilkEncoder, encStatus); stream_channels = channels; hybrid_stereo_width_Q14 = 16384; prev_HB_gain = 32767; first = 1; mode = OpusMode.MODE_HYBRID; bandwidth = OpusBandwidth.OPUS_BANDWIDTH_FULLBAND; variable_HP_smth2_Q15 = Inlines.silk_LSHIFT(Inlines.silk_lin2log(60), 8); } [Obsolete("Use OpusCodecFactory methods which can give you native code if supported by your platform")] public OpusEncoder(int Fs, int channels, OpusApplication application) { if (Fs != 48000 && Fs != 24000 && Fs != 16000 && Fs != 12000 && Fs != 8000) { throw new ArgumentException("Sample rate is invalid (must be 8/12/16/24/48 Khz)"); } if (channels != 1 && channels != 2) { throw new ArgumentException("Number of channels must be 1 or 2"); } int num = opus_init_encoder(Fs, channels, application); switch (num) { case -1: throw new ArgumentException("OPUS_BAD_ARG when creating encoder"); default: throw new OpusException("Error while initializing encoder: " + CodecHelpers.opus_strerror(num), num); case 0: break; } } internal int opus_init_encoder(int Fs, int channels, OpusApplication application) { if ((Fs != 48000 && Fs != 24000 && Fs != 16000 && Fs != 12000 && Fs != 8000) || (channels != 1 && channels != 2) || application == OpusApplication.OPUS_APPLICATION_UNIMPLEMENTED) { return -1; } Reset(); SilkEncoder silkEncoder = SilkEncoder; CeltEncoder celt_Encoder = Celt_Encoder; stream_channels = (this.channels = channels); this.Fs = Fs; if (EncodeAPI.silk_InitEncoder(silkEncoder, silk_mode) != 0) { return -3; } silk_mode.nChannelsAPI = channels; silk_mode.nChannelsInternal = channels; silk_mode.API_sampleRate = this.Fs; silk_mode.maxInternalSampleRate = 16000; silk_mode.minInternalSampleRate = 8000; silk_mode.desiredInternalSampleRate = 16000; silk_mode.payloadSize_ms = 20; silk_mode.bitRate = 25000; silk_mode.packetLossPercentage = 0; silk_mode.complexity = 9; silk_mode.useInBandFEC = 0; silk_mode.useDTX = 0; silk_mode.useCBR = 0; silk_mode.reducedDependency = 0; if (celt_Encoder.celt_encoder_init(Fs, channels) != 0) { return -3; } celt_Encoder.SetSignalling(0); celt_Encoder.SetComplexity(silk_mode.complexity); use_vbr = 1; vbr_constraint = 1; user_bitrate_bps = -1000; bitrate_bps = 3000 + Fs * channels; this.application = application; signal_type = OpusSignal.OPUS_SIGNAL_AUTO; user_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_AUTO; max_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_FULLBAND; force_channels = -1000; user_forced_mode = OpusMode.MODE_AUTO; voice_ratio = -1; encoder_buffer = this.Fs / 100; lsb_depth = 24; variable_duration = OpusFramesize.OPUS_FRAMESIZE_ARG; delay_compensation = this.Fs / 250; hybrid_stereo_width_Q14 = 16384; prev_HB_gain = 32767; variable_HP_smth2_Q15 = Inlines.silk_LSHIFT(Inlines.silk_lin2log(60), 8); first = 1; mode = OpusMode.MODE_HYBRID; bandwidth = OpusBandwidth.OPUS_BANDWIDTH_FULLBAND; Analysis.tonality_analysis_init(analysis); return 0; } internal int user_bitrate_to_bitrate(int user_bitrate, int frame_size, int max_data_bytes) { if (frame_size == 0) { frame_size = Fs / 400; } return user_bitrate switch { -1000 => 60 * Fs / frame_size + Fs * channels, -1 => max_data_bytes * 8 * Fs / frame_size, _ => user_bitrate, }; } internal int opus_encode_native(ReadOnlySpan pcm, int pcm_ptr, int frame_size, Span data, int data_ptr, int out_data_bytes, int lsb_depth, ReadOnlySpan analysis_pcm, int analysis_size, int c1, int c2, int analysis_channels, Downmix.downmix_func downmix, int float_api) { int num = 0; EntropyCoder entropyCoder = new EntropyCoder(); int num2 = 0; int startBand = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; uint num7 = 0u; AnalysisInfo analysisInfo = new AnalysisInfo(); int num8 = -1; int read_subframe = -1; int num9 = Inlines.IMIN(1276, out_data_bytes); rangeFinal = 0u; if ((variable_duration == (OpusFramesize)0 && 400 * frame_size != Fs && 200 * frame_size != Fs && 100 * frame_size != Fs && 50 * frame_size != Fs && 25 * frame_size != Fs && 50 * frame_size != 3 * Fs) || 400 * frame_size < Fs || num9 <= 0) { return -1; } SilkEncoder silkEncoder = SilkEncoder; CeltEncoder celt_Encoder = Celt_Encoder; int num10 = ((application != OpusApplication.OPUS_APPLICATION_RESTRICTED_LOWDELAY) ? delay_compensation : 0); lsb_depth = Inlines.IMIN(lsb_depth, this.lsb_depth); CeltMode celtMode = celt_Encoder.GetMode(); voice_ratio = -1; if (analysis.enabled) { analysisInfo.valid = 0; if ((_vqLevel.HasValue || silk_mode.complexity >= 7) && Fs == 48000) { num8 = analysis.read_pos; read_subframe = analysis.read_subframe; Analysis.run_analysis(analysis, celtMode, analysis_pcm, analysis_size, frame_size, c1, c2, analysis_channels, Fs, lsb_depth, downmix, analysisInfo); } detected_bandwidth = (OpusBandwidth)0; if (analysisInfo.valid != 0) { if (signal_type == OpusSignal.OPUS_SIGNAL_AUTO) { voice_ratio = (int)Math.Floor(0.5f + 100f * (1f - analysisInfo.music_prob)); } int num11 = analysisInfo.bandwidth; if (num11 <= 12) { detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND; } else if (num11 <= 14) { detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND; } else if (num11 <= 16) { detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND; } else if (num11 <= 18) { detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND; } else { detected_bandwidth = OpusBandwidth.OPUS_BANDWIDTH_FULLBAND; } if (_vqLevel.HasValue) { user_bitrate_bps = GetVariableQualityBitrate(_vqLevel.Value, analysis.music_prob); } } } int num12 = ((channels == 2 && force_channels != 1) ? CodecHelpers.compute_stereo_width(pcm, pcm_ptr, frame_size, Fs, width_mem) : 0); int num13 = num10; bitrate_bps = user_bitrate_to_bitrate(user_bitrate_bps, frame_size, num9); int num14 = Fs / frame_size; if (use_vbr == 0) { int num15 = 3 * Fs / frame_size; int num16 = Inlines.IMIN((3 * bitrate_bps / 8 + num15 / 2) / num15, num9); bitrate_bps = num16 * num15 * 8 / 3; num9 = num16; } if (num9 < 3 || bitrate_bps < 3 * num14 * 8 || (num14 < 50 && (num9 * num14 < 300 || bitrate_bps < 2400))) { OpusMode opusMode = mode; OpusBandwidth opusBandwidth = ((bandwidth == (OpusBandwidth)0) ? OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND : bandwidth); if (opusMode == (OpusMode)0) { opusMode = OpusMode.MODE_SILK_ONLY; } if (num14 > 100) { opusMode = OpusMode.MODE_CELT_ONLY; } if (num14 < 50) { opusMode = OpusMode.MODE_SILK_ONLY; } if (opusMode == OpusMode.MODE_SILK_ONLY && opusBandwidth > OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND) { opusBandwidth = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND; } else if (opusMode == OpusMode.MODE_CELT_ONLY && opusBandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) { opusBandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND; } else if (opusMode == OpusMode.MODE_HYBRID && opusBandwidth <= OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND) { opusBandwidth = OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND; } data[data_ptr] = CodecHelpers.gen_toc(opusMode, num14, opusBandwidth, stream_channels); num = 1; if (use_vbr == 0) { num = OpusRepacketizer.PadPacket(data, data_ptr, num, num9); if (num == 0) { num = num9; } } return num; } int num17 = num14 * num9 * 8; int num18 = bitrate_bps - (40 * channels + 20) * (Fs / frame_size - 50); int num19; if (signal_type == OpusSignal.OPUS_SIGNAL_VOICE) { num19 = 127; } else if (signal_type == OpusSignal.OPUS_SIGNAL_MUSIC) { num19 = 0; } else if (voice_ratio < 0) { num19 = ((application != OpusApplication.OPUS_APPLICATION_VOIP) ? 48 : 115); } else { num19 = voice_ratio * 327 >> 8; if (application == OpusApplication.OPUS_APPLICATION_AUDIO) { num19 = Inlines.IMIN(num19, 115); } } if (force_channels != -1000 && channels == 2) { stream_channels = force_channels; } else if (channels == 2) { int num20 = 30000 + (0 >> 14); num20 = ((stream_channels != 2) ? (num20 + 1000) : (num20 - 1000)); stream_channels = ((num18 <= num20) ? 1 : 2); } else { stream_channels = channels; } num18 = bitrate_bps - (40 * stream_channels + 20) * (Fs / frame_size - 50); if (application == OpusApplication.OPUS_APPLICATION_RESTRICTED_LOWDELAY) { mode = OpusMode.MODE_CELT_ONLY; } else if (user_forced_mode == OpusMode.MODE_AUTO) { int num21 = Inlines.MULT16_32_Q15(32767 - num12, Tables.mode_thresholds[0][0]) + Inlines.MULT16_32_Q15(num12, Tables.mode_thresholds[1][0]); int num22 = Inlines.MULT16_32_Q15(32767 - num12, Tables.mode_thresholds[1][1]) + Inlines.MULT16_32_Q15(num12, Tables.mode_thresholds[1][1]); int num23 = num22 + (num19 * num19 * (num21 - num22) >> 14); if (application == OpusApplication.OPUS_APPLICATION_VOIP) { num23 += 8000; } if (prev_mode == OpusMode.MODE_CELT_ONLY) { num23 -= 4000; } else if (prev_mode > (OpusMode)0) { num23 += 4000; } mode = ((num18 >= num23) ? OpusMode.MODE_CELT_ONLY : OpusMode.MODE_SILK_ONLY); if (silk_mode.useInBandFEC != 0 && silk_mode.packetLossPercentage > 128 - num19 >> 4) { mode = OpusMode.MODE_SILK_ONLY; } if (silk_mode.useDTX != 0 && num19 > 100) { mode = OpusMode.MODE_SILK_ONLY; } } else { mode = user_forced_mode; } if (mode != OpusMode.MODE_CELT_ONLY && frame_size < Fs / 100) { mode = OpusMode.MODE_CELT_ONLY; } if (lfe != 0) { mode = OpusMode.MODE_CELT_ONLY; } if (num9 < ((num14 > 50) ? 12000 : 8000) * frame_size / (Fs * 8)) { mode = OpusMode.MODE_CELT_ONLY; } if (stream_channels == 1 && prev_channels == 2 && silk_mode.toMono == 0 && mode != OpusMode.MODE_CELT_ONLY && prev_mode != OpusMode.MODE_CELT_ONLY) { silk_mode.toMono = 1; stream_channels = 2; } else { silk_mode.toMono = 0; } if (prev_mode > (OpusMode)0 && ((mode != OpusMode.MODE_CELT_ONLY && prev_mode == OpusMode.MODE_CELT_ONLY) || (mode == OpusMode.MODE_CELT_ONLY && prev_mode != OpusMode.MODE_CELT_ONLY))) { num3 = 1; num5 = ((mode != OpusMode.MODE_CELT_ONLY) ? 1 : 0); if (num5 == 0) { if (frame_size >= Fs / 100) { mode = prev_mode; num6 = 1; } else { num3 = 0; } } } if (silk_bw_switch != 0) { num3 = 1; num5 = 1; silk_bw_switch = 0; num2 = 1; } if (num3 != 0) { num4 = Inlines.IMIN(257, num9 * (Fs / 200) / (frame_size + Fs / 200)); if (use_vbr != 0) { num4 = Inlines.IMIN(num4, bitrate_bps / 1600); } } if (mode != OpusMode.MODE_CELT_ONLY && prev_mode == OpusMode.MODE_CELT_ONLY) { EncControlState encStatus = new EncControlState(); EncodeAPI.silk_InitEncoder(silkEncoder, encStatus); num2 = 1; } if (mode == OpusMode.MODE_CELT_ONLY || first != 0 || silk_mode.allowBandwidthSwitch != 0) { int[] array = new int[8]; OpusBandwidth opusBandwidth2 = OpusBandwidth.OPUS_BANDWIDTH_FULLBAND; int num24 = num18; if (mode != OpusMode.MODE_CELT_ONLY) { num24 = num24 * (45 + silk_mode.complexity) / 50; if (use_vbr == 0) { num24 -= 1000; } } int[] array2; int[] array3; if (channels == 2 && force_channels != 1) { array2 = Tables.stereo_voice_bandwidth_thresholds; array3 = Tables.stereo_music_bandwidth_thresholds; } else { array2 = Tables.mono_voice_bandwidth_thresholds; array3 = Tables.mono_music_bandwidth_thresholds; } for (int i = 0; i < 8; i++) { array[i] = array3[i] + (num19 * num19 * (array2[i] - array3[i]) >> 14); } int num25; do { num25 = array[2 * (int)(opusBandwidth2 - 1102)]; int num26 = array[2 * (int)(opusBandwidth2 - 1102) + 1]; if (first == 0) { num25 = ((bandwidth < opusBandwidth2) ? (num25 + num26) : (num25 - num26)); } } while (num24 < num25 && --opusBandwidth2 > OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND); bandwidth = opusBandwidth2; if (first == 0 && mode != OpusMode.MODE_CELT_ONLY && silk_mode.inWBmodeWithoutVariableLP == 0 && bandwidth > OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND) { bandwidth = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND; } } if (bandwidth > max_bandwidth) { bandwidth = max_bandwidth; } if (user_bandwidth != OpusBandwidth.OPUS_BANDWIDTH_AUTO) { bandwidth = user_bandwidth; } if (mode != OpusMode.MODE_CELT_ONLY && num17 < 15000) { bandwidth = OpusBandwidthHelpers.MIN(bandwidth, OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND); } if (Fs <= 24000 && bandwidth > OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND) { bandwidth = OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND; } if (Fs <= 16000 && bandwidth > OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND) { bandwidth = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND; } if (Fs <= 12000 && bandwidth > OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) { bandwidth = OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND; } if (Fs <= 8000 && bandwidth > OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) { bandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND; } if (detected_bandwidth != 0 && user_bandwidth == OpusBandwidth.OPUS_BANDWIDTH_AUTO) { detected_bandwidth = OpusBandwidthHelpers.MAX(b: (num18 <= 18000 * stream_channels && mode == OpusMode.MODE_CELT_ONLY) ? OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND : ((num18 <= 24000 * stream_channels && mode == OpusMode.MODE_CELT_ONLY) ? OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND : ((num18 <= 30000 * stream_channels) ? OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND : ((num18 > 44000 * stream_channels) ? OpusBandwidth.OPUS_BANDWIDTH_FULLBAND : OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND))), a: detected_bandwidth); bandwidth = OpusBandwidthHelpers.MIN(bandwidth, detected_bandwidth); } celt_Encoder.SetLSBDepth(lsb_depth); if (mode == OpusMode.MODE_CELT_ONLY && bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) { bandwidth = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND; } if (lfe != 0) { bandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND; } if (frame_size > Fs / 50 && (mode == OpusMode.MODE_CELT_ONLY || bandwidth > OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND)) { if (analysis.enabled && num8 != -1) { analysis.read_pos = num8; analysis.read_subframe = read_subframe; } int num27 = ((frame_size > Fs / 25) ? 3 : 2); int num28 = Inlines.IMIN(1276, (out_data_bytes - 3) / num27); byte[] array4 = new byte[num27 * num28]; OpusRepacketizer opusRepacketizer = new OpusRepacketizer(); OpusMode opusMode2 = user_forced_mode; OpusBandwidth opusBandwidth3 = user_bandwidth; int num29 = force_channels; user_forced_mode = mode; user_bandwidth = bandwidth; force_channels = stream_channels; int toMono = silk_mode.toMono; if (toMono != 0) { force_channels = 1; } else { prev_channels = stream_channels; } for (int i = 0; i < num27; i++) { silk_mode.toMono = 0; if (num6 != 0 && i == num27 - 1) { user_forced_mode = OpusMode.MODE_CELT_ONLY; } int num30 = opus_encode_native(pcm, pcm_ptr + i * (channels * Fs / 50), Fs / 50, array4, i * num28, num28, lsb_depth, null, 0, c1, c2, analysis_channels, downmix, float_api); if (num30 < 0) { return -3; } num = opusRepacketizer.AddPacket(array4, i * num28, num30); if (num < 0) { return -3; } } num = opusRepacketizer.opus_repacketizer_out_range_impl(maxlen: (use_vbr == 0) ? Inlines.IMIN(3 * bitrate_bps / (1200 / num27), out_data_bytes) : out_data_bytes, begin: 0, end: num27, data: data, data_ptr: data_ptr, self_delimited: 0, pad: (use_vbr == 0) ? 1 : 0); if (num < 0) { return -3; } user_forced_mode = opusMode2; user_bandwidth = opusBandwidth3; force_channels = num29; silk_mode.toMono = toMono; return num; } OpusBandwidth opusBandwidth4 = bandwidth; if (mode == OpusMode.MODE_SILK_ONLY && opusBandwidth4 > OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND) { mode = OpusMode.MODE_HYBRID; } if (mode == OpusMode.MODE_HYBRID && opusBandwidth4 <= OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND) { mode = OpusMode.MODE_SILK_ONLY; } int num31 = Inlines.IMIN(num9 - num4, bitrate_bps * frame_size / (Fs * 8)) - 1; data_ptr++; entropyCoder.enc_init((uint)(num9 - 1)); short[] array5 = new short[(num13 + frame_size) * channels]; Arrays.MemCopy(delay_buffer, (encoder_buffer - num13) * channels, array5, 0, num13 * channels); variable_HP_smth2_Q15 = Inlines.silk_SMLAWB(b32: ((mode != OpusMode.MODE_CELT_ONLY) ? silkEncoder.state_Fxx[0].variable_HP_smth1_Q15 : Inlines.silk_LSHIFT(Inlines.silk_lin2log(60), 8)) - variable_HP_smth2_Q15, a32: variable_HP_smth2_Q15, c32: 983); int cutoff_Hz = Inlines.silk_log2lin(Inlines.silk_RSHIFT(variable_HP_smth2_Q15, 8)); if (application == OpusApplication.OPUS_APPLICATION_VOIP) { CodecHelpers.hp_cutoff(pcm, pcm_ptr, cutoff_Hz, array5, num13 * channels, hp_mem, frame_size, channels, Fs); } else { CodecHelpers.dc_reject(pcm, pcm_ptr, 3, array5, num13 * channels, hp_mem, frame_size, channels, Fs); } int num32 = 32767; if (mode != OpusMode.MODE_CELT_ONLY) { short[] array6 = new short[channels * frame_size]; int num33 = 8 * num31 * num14; if (mode == OpusMode.MODE_HYBRID) { silk_mode.bitRate = stream_channels * (5000 + ((Fs == 100 * frame_size) ? 1000 : 0)); if (opusBandwidth4 == OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND) { silk_mode.bitRate += (num33 - silk_mode.bitRate) * 2 / 3; } else { silk_mode.bitRate += (num33 - silk_mode.bitRate) * 3 / 5; } if (silk_mode.bitRate > num33 * 4 / 5) { silk_mode.bitRate = num33 * 4 / 5; } if (energy_masking == null) { int num34 = num33 - silk_mode.bitRate; int num35 = ((opusBandwidth4 == OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND) ? 3000 : 3600); num32 = Inlines.SHL32(num34, 9) / Inlines.SHR32(num34 + stream_channels * num35, 6); num32 = ((num32 < 28086) ? (num32 + 4681) : 32767); } } else { silk_mode.bitRate = num33; } if (energy_masking != null && use_vbr != 0 && lfe == 0) { int num36 = 0; int num37 = 17; short a = 16000; if (bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) { num37 = 13; a = 8000; } else if (bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) { num37 = 15; a = 12000; } for (int j = 0; j < channels; j++) { for (int i = 0; i < num37; i++) { int num38 = Inlines.MAX16(Inlines.MIN16(energy_masking[21 * j + i], 512), -2048); if (num38 > 0) { num38 = Inlines.HALF16(num38); } num36 += num38; } } int num39 = num36 / num37 * channels; num39 += 205; int a2 = Inlines.PSHR32(Inlines.MULT16_16(a, num39), 10); a2 = Inlines.MAX32(a2, -2 * silk_mode.bitRate / 3); if (bandwidth == OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND || bandwidth == OpusBandwidth.OPUS_BANDWIDTH_FULLBAND) { silk_mode.bitRate += 3 * a2 / 5; } else { silk_mode.bitRate += a2; } num31 += a2 * frame_size / (8 * Fs); } silk_mode.payloadSize_ms = 1000 * frame_size / Fs; silk_mode.nChannelsAPI = channels; silk_mode.nChannelsInternal = stream_channels; switch (opusBandwidth4) { case OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND: silk_mode.desiredInternalSampleRate = 8000; break; case OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND: silk_mode.desiredInternalSampleRate = 12000; break; default: silk_mode.desiredInternalSampleRate = 16000; break; } if (mode == OpusMode.MODE_HYBRID) { silk_mode.minInternalSampleRate = 16000; } else { silk_mode.minInternalSampleRate = 8000; } if (mode == OpusMode.MODE_SILK_ONLY) { int num40 = num17; silk_mode.maxInternalSampleRate = 16000; if (num14 > 50) { num40 = num40 * 2 / 3; } if (num40 < 13000) { silk_mode.maxInternalSampleRate = 12000; silk_mode.desiredInternalSampleRate = Inlines.IMIN(12000, silk_mode.desiredInternalSampleRate); } if (num40 < 9600) { silk_mode.maxInternalSampleRate = 8000; silk_mode.desiredInternalSampleRate = Inlines.IMIN(8000, silk_mode.desiredInternalSampleRate); } } else { silk_mode.maxInternalSampleRate = 16000; } silk_mode.useCBR = ((use_vbr == 0) ? 1 : 0); int num41 = Inlines.IMIN(1275, num9 - 1 - num4); silk_mode.maxBits = num41 * 8; if (mode == OpusMode.MODE_HYBRID) { silk_mode.maxBits = silk_mode.maxBits * 9 / 10; } if (silk_mode.useCBR != 0) { silk_mode.maxBits = silk_mode.bitRate * frame_size / (Fs * 8) * 8; silk_mode.bitRate = Inlines.IMAX(1, silk_mode.bitRate - 2000); } if (num2 != 0) { BoxedValueInt nBytesOut = new BoxedValueInt(); int num42 = channels * (encoder_buffer - delay_compensation - Fs / 400); CodecHelpers.gain_fade(delay_buffer, num42, 0, 32767, celtMode.overlap, Fs / 400, channels, celtMode.window, Fs); Arrays.MemSetShort(delay_buffer, 0, num42); Arrays.MemCopy(delay_buffer, 0, array6, 0, encoder_buffer * channels); EncodeAPI.silk_Encode(silkEncoder, silk_mode, array6, encoder_buffer, null, data.Slice(data_ptr), nBytesOut, 1); } Arrays.MemCopy(array5, num13 * channels, array6, 0, frame_size * channels); BoxedValueInt boxedValueInt = new BoxedValueInt(num41); num = EncodeAPI.silk_Encode(silkEncoder, silk_mode, array6, frame_size, entropyCoder, data.Slice(data_ptr), boxedValueInt, 0); num41 = boxedValueInt.Val; if (num != 0) { return -3; } if (num41 == 0) { rangeFinal = 0u; data[data_ptr - 1] = CodecHelpers.gen_toc(mode, Fs / frame_size, opusBandwidth4, stream_channels); return 1; } if (mode == OpusMode.MODE_SILK_ONLY) { if (silk_mode.internalSampleRate == 8000) { opusBandwidth4 = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND; } else if (silk_mode.internalSampleRate == 12000) { opusBandwidth4 = OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND; } else if (silk_mode.internalSampleRate == 16000) { opusBandwidth4 = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND; } } silk_mode.opusCanSwitch = silk_mode.switchReady; if (silk_mode.opusCanSwitch != 0) { num3 = 1; num5 = 0; silk_bw_switch = 1; } } int endBand = 21; switch (opusBandwidth4) { case OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND: endBand = 13; break; case OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND: case OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND: endBand = 17; break; case OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND: endBand = 19; break; case OpusBandwidth.OPUS_BANDWIDTH_FULLBAND: endBand = 21; break; } celt_Encoder.SetEndBand(endBand); celt_Encoder.SetChannels(stream_channels); celt_Encoder.SetBitrate(-1); int num44; if (mode != OpusMode.MODE_SILK_ONLY) { int prediction = 2; celt_Encoder.SetVBR(value: false); if (silk_mode.reducedDependency != 0) { prediction = 0; } celt_Encoder.SetPrediction(prediction); if (mode == OpusMode.MODE_HYBRID) { int num43 = entropyCoder.tell() + 7 >> 3; if (num3 != 0) { num43 += ((mode != OpusMode.MODE_HYBRID) ? 1 : 3); } num44 = ((use_vbr == 0) ? ((num43 > num31) ? num43 : num31) : (num43 + num31 - silk_mode.bitRate * frame_size / (8 * Fs))); } else if (use_vbr != 0) { int num45 = 0; if (analysis.enabled && variable_duration == OpusFramesize.OPUS_FRAMESIZE_VARIABLE && frame_size != Fs / 50) { num45 = (60 * stream_channels + 40) * (Fs / frame_size - 50); if (analysisInfo.valid != 0) { num45 = (int)((float)num45 * (1f + 0.5f * analysisInfo.tonality)); } } celt_Encoder.SetVBR(value: true); celt_Encoder.SetVBRConstraint(vbr_constraint != 0); celt_Encoder.SetBitrate(bitrate_bps + num45); num44 = num9 - 1 - num4; } else { num44 = num31; } } else { num44 = 0; } short[] array7 = new short[channels * Fs / 400]; if (mode != OpusMode.MODE_SILK_ONLY && mode != prev_mode && prev_mode > (OpusMode)0) { Arrays.MemCopy(delay_buffer, (encoder_buffer - num13 - Fs / 400) * channels, array7, 0, channels * Fs / 400); } if (channels * (encoder_buffer - (frame_size + num13)) > 0) { Arrays.MemMoveShort(delay_buffer, channels * frame_size, 0, channels * (encoder_buffer - frame_size - num13)); Arrays.MemCopy(array5, 0, delay_buffer, channels * (encoder_buffer - frame_size - num13), (frame_size + num13) * channels); } else { Arrays.MemCopy(array5, (frame_size + num13 - encoder_buffer) * channels, delay_buffer, 0, encoder_buffer * channels); } if (prev_HB_gain < 32767 || num32 < 32767) { CodecHelpers.gain_fade(array5, 0, prev_HB_gain, num32, celtMode.overlap, frame_size, channels, celtMode.window, Fs); } prev_HB_gain = num32; if (mode != OpusMode.MODE_HYBRID || stream_channels == 1) { silk_mode.stereoWidth_Q14 = Inlines.IMIN(16384, 2 * Inlines.IMAX(0, num18 - 30000)); } if (energy_masking == null && channels == 2 && (hybrid_stereo_width_Q14 < 16384 || silk_mode.stereoWidth_Q14 < 16384)) { int num46 = hybrid_stereo_width_Q14; int stereoWidth_Q = silk_mode.stereoWidth_Q14; num46 = ((num46 == 16384) ? 32767 : Inlines.SHL16(num46, 1)); stereoWidth_Q = ((stereoWidth_Q == 16384) ? 32767 : Inlines.SHL16(stereoWidth_Q, 1)); CodecHelpers.stereo_fade(array5, num46, stereoWidth_Q, celtMode.overlap, frame_size, channels, celtMode.window, Fs); hybrid_stereo_width_Q14 = (short)silk_mode.stereoWidth_Q14; } if (mode != OpusMode.MODE_CELT_ONLY && entropyCoder.tell() + 17 + 20 * ((mode == OpusMode.MODE_HYBRID) ? 1 : 0) <= 8 * (num9 - 1)) { if (mode == OpusMode.MODE_HYBRID && (num3 != 0 || entropyCoder.tell() + 37 <= 8 * num44)) { entropyCoder.enc_bit_logp(data.Slice(data_ptr), num3, 12u); } if (num3 != 0) { entropyCoder.enc_bit_logp(data.Slice(data_ptr), num5, 1u); int a3 = ((mode != OpusMode.MODE_HYBRID) ? (num9 - 1 - (entropyCoder.tell() + 7 >> 3)) : (num9 - 1 - num44)); num4 = Inlines.IMIN(a3, bitrate_bps / 1600); num4 = Inlines.IMIN(257, Inlines.IMAX(2, num4)); if (mode == OpusMode.MODE_HYBRID) { entropyCoder.enc_uint(data.Slice(data_ptr), (uint)(num4 - 2), 256u); } } } else { num3 = 0; } if (num3 == 0) { silk_bw_switch = 0; num4 = 0; } if (mode != OpusMode.MODE_CELT_ONLY) { startBand = 17; } if (mode == OpusMode.MODE_SILK_ONLY) { num = entropyCoder.tell() + 7 >> 3; entropyCoder.enc_done(data.Slice(data_ptr)); num44 = num; } else { num44 = Inlines.IMIN(num9 - 1 - num4, num44); entropyCoder.enc_shrink(data.Slice(data_ptr), (uint)num44); } if ((analysis.enabled && num3 != 0) || mode != OpusMode.MODE_SILK_ONLY) { celt_Encoder.SetAnalysis(analysisInfo); } if (num3 != 0 && num5 != 0) { celt_Encoder.SetStartBand(0); celt_Encoder.SetVBR(value: false); if (celt_Encoder.celt_encode_with_ec(array5, 0, Fs / 200, data, data_ptr + num44, num4, null) < 0) { return -3; } num7 = celt_Encoder.GetFinalRange(); celt_Encoder.ResetState(); } celt_Encoder.SetStartBand(startBand); if (mode != OpusMode.MODE_SILK_ONLY) { if (mode != prev_mode && prev_mode > (OpusMode)0) { Span compressed = stackalloc byte[2]; celt_Encoder.ResetState(); celt_Encoder.celt_encode_with_ec(array7, 0, Fs / 400, compressed, 0, 2, null); celt_Encoder.SetPrediction(0); } if (entropyCoder.tell() <= 8 * num44) { num = celt_Encoder.celt_encode_with_ec(array5, 0, frame_size, data.Slice(data_ptr), 0, num44, entropyCoder); if (num < 0) { return -3; } } } if (num3 != 0 && num5 == 0) { Span compressed2 = stackalloc byte[2]; int num47 = Fs / 200; int num48 = Fs / 400; celt_Encoder.ResetState(); celt_Encoder.SetStartBand(0); celt_Encoder.SetPrediction(0); celt_Encoder.celt_encode_with_ec(array5, channels * (frame_size - num47 - num48), num48, compressed2, 0, 2, null); if (celt_Encoder.celt_encode_with_ec(array5, channels * (frame_size - num47), num47, data, data_ptr + num44, num4, null) < 0) { return -3; } num7 = celt_Encoder.GetFinalRange(); } data_ptr--; data[data_ptr] = CodecHelpers.gen_toc(mode, Fs / frame_size, opusBandwidth4, stream_channels); rangeFinal = entropyCoder.rng ^ num7; if (num6 != 0) { prev_mode = OpusMode.MODE_CELT_ONLY; } else { prev_mode = mode; } prev_channels = stream_channels; prev_framesize = frame_size; first = 0; if (entropyCoder.tell() > (num9 - 1) * 8) { if (num9 < 2) { return -2; } data[data_ptr + 1] = 0; num = 1; rangeFinal = 0u; } else if (mode == OpusMode.MODE_SILK_ONLY && num3 == 0) { while (num > 2 && data[data_ptr + num] == 0) { num--; } } num += 1 + num4; if (use_vbr == 0) { if (OpusRepacketizer.PadPacket(data, data_ptr, num, num9) != 0) { return -3; } num = num9; } return num; } private static int GetVariableQualityBitrate(int vqLevel, float music_prob) { float num = vqTable[vqLevel][0]; float num2 = vqTable[vqLevel][1]; float num3 = (float)Math.Sqrt(music_prob); return (int)(num2 * num3 + num * (1f - num3)); } [Obsolete("Use Span<> overrides if possible")] public int Encode(short[] in_pcm, int pcm_offset, int frame_size, byte[] out_data, int out_data_offset, int max_data_bytes) { return Encode(in_pcm.AsSpan(pcm_offset), frame_size, out_data.AsSpan(out_data_offset), max_data_bytes); } public int Encode(ReadOnlySpan in_pcm, int frame_size, Span out_data, int max_data_bytes) { if (max_data_bytes > out_data.Length) { throw new ArgumentException($"Output buffer is too small: Stated size is {max_data_bytes} bytes, actual size is {out_data.Length} bytes"); } int num2 = CodecHelpers.compute_frame_size(delay_compensation: (application != OpusApplication.OPUS_APPLICATION_RESTRICTED_LOWDELAY) ? delay_compensation : 0, analysis_pcm: in_pcm, frame_size: frame_size, variable_duration: variable_duration, C: channels, Fs: Fs, bitrate_bps: bitrate_bps, downmix: Downmix.downmix_int, subframe_mem: analysis.subframe_mem, analysis_enabled: analysis.enabled); if (num2 > in_pcm.Length) { throw new ArgumentException($"Not enough samples provided in input signal: Expected {num2} samples, found {in_pcm.Length}"); } try { int num3 = opus_encode_native(in_pcm, 0, num2, out_data, 0, max_data_bytes, 16, in_pcm, frame_size, 0, -2, channels, Downmix.downmix_int, 0); if (num3 < 0) { if (num3 == -1) { throw new ArgumentException("OPUS_BAD_ARG while encoding"); } throw new OpusException("An error occurred during encoding: " + CodecHelpers.opus_strerror(num3), num3); } return num3; } catch (ArgumentException ex) { throw new OpusException("public error during encoding: " + ex.Message, -1); } } [Obsolete("Use Span<> overrides if possible")] public int Encode(float[] in_pcm, int in_pcm_offset, int frame_size, byte[] out_data, int out_data_offset, int max_data_bytes) { return Encode(in_pcm.AsSpan(in_pcm_offset), frame_size, out_data.AsSpan(out_data_offset), max_data_bytes); } public int Encode(ReadOnlySpan in_pcm, int frame_size, Span out_data, int max_data_bytes) { if (max_data_bytes > out_data.Length) { throw new ArgumentException($"Output buffer is too small: Stated size is {max_data_bytes} bytes, actual size is {out_data.Length} bytes"); } int num2 = CodecHelpers.compute_frame_size(delay_compensation: (application != OpusApplication.OPUS_APPLICATION_RESTRICTED_LOWDELAY) ? delay_compensation : 0, analysis_pcm: in_pcm, frame_size: frame_size, variable_duration: variable_duration, C: channels, Fs: Fs, bitrate_bps: bitrate_bps, downmix: Downmix.downmix_float, subframe_mem: analysis.subframe_mem, analysis_enabled: analysis.enabled); if (num2 > in_pcm.Length) { throw new ArgumentException($"Not enough samples provided in input signal: Expected {num2} samples, found {in_pcm.Length}"); } short[] array = new short[num2 * channels]; for (int i = 0; i < num2 * channels; i++) { array[i] = Inlines.FLOAT2INT16(in_pcm[i]); } try { int num3 = opus_encode_native(array, 0, num2, out_data, 0, max_data_bytes, 16, in_pcm, frame_size, 0, -2, channels, Downmix.downmix_float, 1); if (num3 < 0) { if (num3 == -1) { throw new ArgumentException("OPUS_BAD_ARG while decoding"); } throw new OpusException("An error occurred during encoding: " + CodecHelpers.opus_strerror(num3), num3); } return num3; } catch (ArgumentException ex) { throw new OpusException("public error during encoding: " + ex.Message, -1); } } internal void SetEnergyMask(int[] value) { energy_masking = value; Celt_Encoder.SetEnergyMask(value); } internal CeltMode GetCeltMode() { return Celt_Encoder.GetMode(); } public string GetVersionString() { return CodecHelpers.GetVersionString(); } public void Dispose() { } } public class OpusMSDecoder : IOpusMultiStreamDecoder, IDisposable { internal delegate void opus_copy_channel_out_func(Span dst, int dst_stride, int dst_channel, Span src, int src_ptr, int src_stride, int frame_size); internal ChannelLayout layout = new ChannelLayout(); internal OpusDecoder[] decoders; public OpusBandwidth Bandwidth { get { if (decoders == null || decoders.Length == 0) { throw new InvalidOperationException("Decoder not initialized"); } return decoders[0].Bandwidth; } } public int SampleRate { get { if (decoders == null || decoders.Length == 0) { throw new InvalidOperationException("Decoder not initialized"); } return decoders[0].SampleRate; } } public int NumChannels => layout.nb_channels; public int Gain { get { if (decoders == null || decoders.Length == 0) { return -6; } return decoders[0].Gain; } set { for (int i = 0; i < layout.nb_streams; i++) { decoders[i].Gain = value; } } } public int LastPacketDuration { get { if (decoders == null || decoders.Length == 0) { return -6; } return decoders[0].LastPacketDuration; } } public uint FinalRange { get { uint num = 0u; for (int i = 0; i < layout.nb_streams; i++) { num ^= decoders[i].FinalRange; } return num; } } private OpusMSDecoder(int nb_streams, int nb_coupled_streams) { decoders = new OpusDecoder[nb_streams]; for (int i = 0; i < nb_streams; i++) { decoders[i] = new OpusDecoder(); } } internal int opus_multistream_decoder_init(int Fs, int channels, int streams, int coupled_streams, byte[] mapping) { int num = 0; if (channels > 255 || channels < 1 || coupled_streams > streams || streams < 1 || coupled_streams < 0 || streams > 255 - coupled_streams) { throw new ArgumentException("Invalid channel or coupled stream count"); } layout.nb_channels = channels; layout.nb_streams = streams; layout.nb_coupled_streams = coupled_streams; int i; for (i = 0; i < layout.nb_channels; i++) { layout.mapping[i] = mapping[i]; } if (OpusMultistream.validate_layout(layout) == 0) { throw new ArgumentException("Invalid surround channel layout"); } for (i = 0; i < layout.nb_coupled_streams; i++) { int num2 = decoders[num].opus_decoder_init(Fs, 2); if (num2 != 0) { return num2; } num++; } for (; i < layout.nb_streams; i++) { int num2 = decoders[num].opus_decoder_init(Fs, 1); if (num2 != 0) { return num2; } num++; } return 0; } [Obsolete("Use OpusCodecFactory methods which can give you native code if supported by your platform")] public OpusMSDecoder(int Fs, int channels, int streams, int coupled_streams, byte[] mapping) : this(streams, coupled_streams) { if (channels > 255 || channels < 1 || coupled_streams > streams || streams < 1 || coupled_streams < 0 || streams > 255 - coupled_streams) { throw new ArgumentException("Invalid channel / stream configuration"); } int num = opus_multistream_decoder_init(Fs, channels, streams, coupled_streams, mapping); switch (num) { case -1: throw new ArgumentException("Bad argument while creating MS decoder"); default: throw new OpusException("Could not create MS decoder: " + CodecHelpers.opus_strerror(num), num); case 0: break; } } internal static int opus_multistream_packet_validate(ReadOnlySpan data, int nb_streams, int Fs) { short[] array = new short[48]; int num = 0; int num2 = 0; int num3 = data.Length; for (int i = 0; i < nb_streams; i++) { if (data.Length <= 0) { return -4; } byte out_toc; int payload_offset; int packet_offset; int num4 = OpusPacketInfo.opus_packet_parse_impl(data, num2, num3, (i != nb_streams - 1) ? 1 : 0, out out_toc, null, null, 0, array, 0, out payload_offset, out packet_offset); if (num4 < 0) { return num4; } int numSamples = OpusPacketInfo.GetNumSamples(data.Slice(num2, packet_offset), Fs); if (i != 0 && num != numSamples) { return -4; } num = numSamples; num2 += packet_offset; num3 -= packet_offset; } return num; } internal int opus_multistream_decode_native(ReadOnlySpan data, Span pcm, opus_copy_channel_out_func copy_channel_out, int frame_size, int decode_fec, int soft_clip) { int num = 0; int sampleRate = SampleRate; frame_size = Inlines.IMIN(frame_size, sampleRate / 25 * 3); short[] array = new short[2 * frame_size]; int num2 = 0; if (data.Length == 0) { num = 1; } if (data.Length < 0) { return -1; } if (num == 0 && data.Length < 2 * layout.nb_streams - 1) { return -4; } if (num == 0) { int num3 = opus_multistream_packet_validate(data, layout.nb_streams, sampleRate); if (num3 < 0) { return num3; } if (num3 > frame_size) { return -2; } } int num4 = 0; int num5 = data.Length; for (int i = 0; i < layout.nb_streams; i++) { OpusDecoder opusDecoder = decoders[num2++]; if (num == 0 && data.Length <= 0) { return -3; } int packet_offset; int num6 = opusDecoder.opus_decode_native(data, num4, num5, array, 0, frame_size, decode_fec, (i != layout.nb_streams - 1) ? 1 : 0, out packet_offset, soft_clip); num4 += packet_offset; num5 -= packet_offset; if (num6 <= 0) { return num6; } frame_size = num6; if (i < layout.nb_coupled_streams) { int prev = -1; int num7; while ((num7 = OpusMultistream.get_left_channel(layout, i, prev)) != -1) { copy_channel_out(pcm, layout.nb_channels, num7, array, 0, 2, frame_size); prev = num7; } prev = -1; while ((num7 = OpusMultistream.get_right_channel(layout, i, prev)) != -1) { copy_channel_out(pcm, layout.nb_channels, num7, array, 1, 2, frame_size); prev = num7; } } else { int prev2 = -1; int num8; while ((num8 = OpusMultistream.get_mono_channel(layout, i, prev2)) != -1) { copy_channel_out(pcm, layout.nb_channels, num8, array, 0, 1, frame_size); prev2 = num8; } } } for (int j = 0; j < layout.nb_channels; j++) { if (layout.mapping[j] == byte.MaxValue) { copy_channel_out(pcm, layout.nb_channels, j, null, 0, 0, frame_size); } } return frame_size; } internal static void opus_copy_channel_out_float(Span dst, int dst_stride, int dst_channel, Span src, int src_ptr, int src_stride, int frame_size) { if (!src.IsEmpty) { for (int i = 0; i < frame_size; i++) { dst[i * dst_stride + dst_channel] = 3.0517578E-05f * (float)src[i * src_stride + src_ptr]; } } else { for (int i = 0; i < frame_size; i++) { dst[i * dst_stride + dst_channel] = 0f; } } } internal static void opus_copy_channel_out_short(Span dst, int dst_stride, int dst_channel, Span src, int src_ptr, int src_stride, int frame_size) { if (!src.IsEmpty) { for (int i = 0; i < frame_size; i++) { dst[i * dst_stride + dst_channel] = src[i * src_stride + src_ptr]; } } else { for (int i = 0; i < frame_size; i++) { dst[i * dst_stride + dst_channel] = 0; } } } [Obsolete("Use Span<> overrides if possible")] public int DecodeMultistream(byte[] data, int data_offset, int len, short[] out_pcm, int out_pcm_offset, int frame_size, bool decode_fec) { if (data == null) { return DecodeMultistream(ReadOnlySpan.Empty, out_pcm.AsSpan(out_pcm_offset), frame_size, decode_fec); } return DecodeMultistream(data.AsSpan(data_offset, len), out_pcm.AsSpan(out_pcm_offset), frame_size, decode_fec); } public int DecodeMultistream(ReadOnlySpan data, Span out_pcm, int frame_size, bool decode_fec) { int num = opus_multistream_decode_native(data, out_pcm, opus_copy_channel_out_short, frame_size, decode_fec ? 1 : 0, 0); if (num < 0) { if (num == -1) { throw new ArgumentException("OPUS_BAD_ARG while decoding"); } throw new OpusException("An error occurred during decoding: " + CodecHelpers.opus_strerror(num), num); } return num; } [Obsolete("Use Span<> overrides if possible")] public int DecodeMultistream(byte[] data, int data_offset, int len, float[] out_pcm, int out_pcm_offset, int frame_size, bool decode_fec) { if (data == null) { return DecodeMultistream(ReadOnlySpan.Empty, out_pcm.AsSpan(out_pcm_offset), frame_size, decode_fec); } return DecodeMultistream(data.AsSpan(data_offset, len), out_pcm.AsSpan(out_pcm_offset), frame_size, decode_fec); } public int DecodeMultistream(ReadOnlySpan data, Span out_pcm, int frame_size, bool decode_fec) { int num = opus_multistream_decode_native(data, out_pcm, opus_copy_channel_out_float, frame_size, decode_fec ? 1 : 0, 0); if (num < 0) { if (num == -1) { throw new ArgumentException("OPUS_BAD_ARG while decoding"); } throw new OpusException("An error occurred during decoding: " + CodecHelpers.opus_strerror(num), num); } return num; } public void ResetState() { for (int i = 0; i < layout.nb_streams; i++) { decoders[i].ResetState(); } } public string GetVersionString() { return CodecHelpers.GetVersionString(); } public OpusDecoder GetMultistreamDecoderState(int streamId) { return decoders[streamId]; } public void Dispose() { } } public class OpusMSEncoder : IOpusMultiStreamEncoder, IDisposable { internal delegate void opus_copy_channel_in_func(Span dst, int dst_ptr, int dst_stride, ReadOnlySpan src, int src_stride, int src_channel, int frame_size); internal readonly ChannelLayout layout = new ChannelLayout(); internal int lfe_stream; internal OpusApplication application = OpusApplication.OPUS_APPLICATION_AUDIO; internal OpusFramesize variable_duration; internal int surround; internal int bitrate_bps; internal readonly float[] subframe_mem = new float[3]; internal readonly OpusEncoder[] encoders; internal readonly int[] window_mem; internal readonly int[] preemph_mem; private static readonly int[] diff_table = new int[17] { 512, 300, 165, 87, 45, 23, 11, 6, 3, 0, 0, 0, 0, 0, 0, 0, 0 }; private const int MS_FRAME_TMP = 3832; public int Bitrate { get { int num = 0; int num2 = 0; for (int i = 0; i < layout.nb_streams; i++) { OpusEncoder opusEncoder = encoders[num2++]; num += opusEncoder.Bitrate; } return num; } set { if (value < 0 && value != -1000 && value != -1) { throw new ArgumentException("Invalid bitrate"); } bitrate_bps = value; } } public OpusApplication Application { get { return encoders[0].Application; } set { for (int i = 0; i < layout.nb_streams; i++) { encoders[i].Application = value; } } } public int ForceChannels { get { return encoders[0].ForceChannels; } set { for (int i = 0; i < layout.nb_streams; i++) { encoders[i].ForceChannels = value; } } } public int NumChannels => layout.nb_channels; public OpusBandwidth MaxBandwidth { get { return encoders[0].MaxBandwidth; } set { for (int i = 0; i < layout.nb_streams; i++) { encoders[i].MaxBandwidth = value; } } } public OpusBandwidth Bandwidth { get { return encoders[0].Bandwidth; } set { for (int i = 0; i < layout.nb_streams; i++) { encoders[i].Bandwidth = value; } } } public bool UseDTX { get { return encoders[0].UseDTX; } set { for (int i = 0; i < layout.nb_streams; i++) { encoders[i].UseDTX = value; } } } public int Complexity { get { return encoders[0].Complexity; } set { for (int i = 0; i < layout.nb_streams; i++) { encoders[i].Complexity = value; } } } public OpusMode ForceMode { get { return encoders[0].ForceMode; } set { for (int i = 0; i < layout.nb_streams; i++) { encoders[i].ForceMode = value; } } } public bool UseInbandFEC { get { return encoders[0].UseInbandFEC; } set { for (int i = 0; i < layout.nb_streams; i++) { encoders[i].UseInbandFEC = value; } } } public int PacketLossPercent { get { return encoders[0].PacketLossPercent; } set { for (int i = 0; i < layout.nb_streams; i++) { encoders[i].PacketLossPercent = value; } } } public bool UseVBR { get { return encoders[0].UseVBR; } set { for (int i = 0; i < layout.nb_streams; i++) { encoders[i].UseVBR = value; } } } public bool UseConstrainedVBR { get { return encoders[0].UseConstrainedVBR; } set { for (int i = 0; i < layout.nb_streams; i++) { encoders[i].UseConstrainedVBR = value; } } } public OpusSignal SignalType { get { return encoders[0].SignalType; } set { for (int i = 0; i < layout.nb_streams; i++) { encoders[i].SignalType = value; } } } public int Lookahead => encoders[0].Lookahead; public int SampleRate => encoders[0].SampleRate; public uint FinalRange { get { uint num = 0u; int num2 = 0; for (int i = 0; i < layout.nb_streams; i++) { num ^= encoders[num2++].FinalRange; } return num; } } public int LSBDepth { get { return encoders[0].LSBDepth; } set { for (int i = 0; i < layout.nb_streams; i++) { encoders[i].LSBDepth = value; } } } public bool PredictionDisabled { get { return encoders[0].PredictionDisabled; } set { for (int i = 0; i < layout.nb_streams; i++) { encoders[i].PredictionDisabled = value; } } } public OpusFramesize ExpertFrameDuration { get { return variable_duration; } set { variable_duration = value; } } private OpusMSEncoder(int nb_streams, int nb_coupled_streams) { if (nb_streams < 1 || nb_coupled_streams > nb_streams || nb_coupled_streams < 0) { throw new ArgumentException("Invalid channel count in MS encoder"); } encoders = new OpusEncoder[nb_streams]; for (int i = 0; i < nb_streams; i++) { encoders[i] = new OpusEncoder(); } int num = nb_coupled_streams * 2 + (nb_streams - nb_coupled_streams); window_mem = new int[num * 120]; preemph_mem = new int[num]; } public void ResetState() { subframe_mem[0] = (subframe_mem[1] = (subframe_mem[2] = 0f)); if (surround != 0) { Arrays.MemSetInt(preemph_mem, 0, layout.nb_channels); Arrays.MemSetInt(window_mem, 0, layout.nb_channels * 120); } int num = 0; for (int i = 0; i < layout.nb_streams; i++) { encoders[num++].ResetState(); } } internal static int validate_encoder_layout(ChannelLayout layout) { for (int i = 0; i < layout.nb_streams; i++) { if (i < layout.nb_coupled_streams) { if (OpusMultistream.get_left_channel(layout, i, -1) == -1) { return 0; } if (OpusMultistream.get_right_channel(layout, i, -1) == -1) { return 0; } } else if (OpusMultistream.get_mono_channel(layout, i, -1) == -1) { return 0; } } return 1; } internal static void channel_pos(int channels, int[] pos) { switch (channels) { case 4: pos[0] = 1; pos[1] = 3; pos[2] = 1; pos[3] = 3; break; case 3: case 5: case 6: pos[0] = 1; pos[1] = 2; pos[2] = 3; pos[3] = 1; pos[4] = 3; pos[5] = 0; break; case 7: pos[0] = 1; pos[1] = 2; pos[2] = 3; pos[3] = 1; pos[4] = 3; pos[5] = 2; pos[6] = 0; break; case 8: pos[0] = 1; pos[1] = 2; pos[2] = 3; pos[3] = 1; pos[4] = 3; pos[5] = 1; pos[6] = 3; pos[7] = 0; break; } } internal static int logSum(int a, int b) { int num; int num2; if (a > b) { num = a; num2 = Inlines.SUB32(Inlines.EXTEND32(a), Inlines.EXTEND32(b)); } else { num = b; num2 = Inlines.SUB32(Inlines.EXTEND32(b), Inlines.EXTEND32(a)); } if (num2 >= 8192) { return num; } int num3 = Inlines.SHR32(num2, 9); int a2 = Inlines.SHL16(num2 - Inlines.SHL16(num3, 9), 6); return num + diff_table[num3] + Inlines.MULT16_16_Q15(a2, Inlines.SUB16(diff_table[num3 + 1], diff_table[num3])); } internal static void surround_analysis(CeltMode celt_mode, ReadOnlySpan pcm, int[] bandLogE, int[] mem, int[] preemph_mem, int len, int overlap, int channels, int rate, opus_copy_channel_in_func copy_channel_in) { int[] array = new int[8]; int[][] array2 = Arrays.InitTwoDimensionalArray(1, 21); int[][] array3 = Arrays.InitTwoDimensionalArray(3, 21); int num = CeltCommon.resampling_factor(rate); int num2 = len * num; int i; for (i = 0; i < celt_mode.maxLM && celt_mode.shortMdctSize << i != num2; i++) { } int[] array4 = new int[num2 + overlap]; short[] array5 = new short[len]; int[][] array6 = Arrays.InitTwoDimensionalArray(1, num2); channel_pos(channels, array); for (int j = 0; j < 3; j++) { for (int k = 0; k < 21; k++) { array3[j][k] = -28672; } } for (int j = 0; j < channels; j++) { Arrays.MemCopy(mem, j * overlap, array4, 0, overlap); copy_channel_in(array5, 0, 1, pcm, channels, j, len); BoxedValueInt boxedValueInt = new BoxedValueInt(preemph_mem[j]); CeltCommon.celt_preemphasis(array5, array4, overlap, num2, 1, num, celt_mode.preemph, boxedValueInt, 0); preemph_mem[j] = boxedValueInt.Val; MDCT.clt_mdct_forward(celt_mode.mdct, array4, 0, array6[0], 0, celt_mode.window, overlap, celt_mode.maxLM - i, 1); if (num != 1) { int k; for (k = 0; k < len; k++) { array6[0][k] *= num; } for (; k < num2; k++) { array6[0][k] = 0; } } Bands.compute_band_energies(celt_mode, array6, array2, 21, 1, i); QuantizeBands.amp2Log2(celt_mode, 21, 21, array2[0], bandLogE, 21 * j, 1); for (int k = 1; k < 21; k++) { bandLogE[21 * j + k] = Inlines.MAX16(bandLogE[21 * j + k], bandLogE[21 * j + k - 1] - 1024); } for (int k = 19; k >= 0; k--) { bandLogE[21 * j + k] = Inlines.MAX16(bandLogE[21 * j + k], bandLogE[21 * j + k + 1] - 2048); } if (array[j] == 1) { for (int k = 0; k < 21; k++) { array3[0][k] = logSum(array3[0][k], bandLogE[21 * j + k]); } } else if (array[j] == 3) { for (int k = 0; k < 21; k++) { array3[2][k] = logSum(array3[2][k], bandLogE[21 * j + k]); } } else if (array[j] == 2) { for (int k = 0; k < 21; k++) { array3[0][k] = logSum(array3[0][k], bandLogE[21 * j + k] - 512); array3[2][k] = logSum(array3[2][k], bandLogE[21 * j + k] - 512); } } Arrays.MemCopy(array4, num2, mem, j * overlap, overlap); } for (int k = 0; k < 21; k++) { array3[1][k] = Inlines.MIN32(array3[0][k], array3[2][k]); } int num3 = Inlines.HALF16(Inlines.celt_log2(32768 / (channels - 1))); for (int j = 0; j < 3; j++) { for (int k = 0; k < 21; k++) { array3[j][k] += num3; } } for (int j = 0; j < channels; j++) { if (array[j] != 0) { int[] array7 = array3[array[j] - 1]; for (int k = 0; k < 21; k++) { bandLogE[21 * j + k] -= array7[k]; } } else { for (int k = 0; k < 21; k++) { bandLogE[21 * j + k] = 0; } } } } internal int opus_multistream_encoder_init(int Fs, int channels, int streams, int coupled_streams, byte[] mapping, OpusApplication application, int surround) { if (channels > 255 || channels < 1 || coupled_streams > streams || streams < 1 || coupled_streams < 0 || streams > 255 - coupled_streams) { return -1; } layout.nb_channels = channels; layout.nb_streams = streams; layout.nb_coupled_streams = coupled_streams; subframe_mem[0] = (subframe_mem[1] = (subframe_mem[2] = 0f)); if (surround == 0) { lfe_stream = -1; } bitrate_bps = -1000; this.application = application; variable_duration = OpusFramesize.OPUS_FRAMESIZE_ARG; int i; for (i = 0; i < layout.nb_channels; i++) { layout.mapping[i] = mapping[i]; } if (OpusMultistream.validate_layout(layout) == 0 || validate_encoder_layout(layout) == 0) { return -1; } int num = 0; for (i = 0; i < layout.nb_coupled_streams; i++) { int num2 = encoders[num].opus_init_encoder(Fs, 2, application); if (num2 != 0) { return num2; } if (i == lfe_stream) { encoders[num].IsLFE = true; } num++; } for (; i < layout.nb_streams; i++) { int num2 = encoders[num].opus_init_encoder(Fs, 1, application); if (i == lfe_stream) { encoders[num].IsLFE = true; } if (num2 != 0) { return num2; } num++; } if (surround != 0) { Arrays.MemSetInt(preemph_mem, 0, channels); Arrays.MemSetInt(window_mem, 0, channels * 120); } this.surround = surround; return 0; } internal int opus_multistream_surround_encoder_init(int Fs, int channels, int mapping_family, out int streams, out int coupled_streams, byte[] mapping, OpusApplication application) { streams = 0; coupled_streams = 0; if (channels > 255 || channels < 1) { return -1; } lfe_stream = -1; if (mapping_family == 0) { switch (channels) { case 1: streams = 1; coupled_streams = 0; mapping[0] = 0; break; case 2: streams = 1; coupled_streams = 1; mapping[0] = 0; mapping[1] = 1; break; default: return -5; } } else if (mapping_family == 1 && channels <= 8 && channels >= 1) { streams = VorbisLayout.vorbis_mappings[channels - 1].nb_streams; coupled_streams = VorbisLayout.vorbis_mappings[channels - 1].nb_coupled_streams; for (int i = 0; i < channels; i++) { mapping[i] = VorbisLayout.vorbis_mappings[channels - 1].mapping[i]; } if (channels >= 6) { lfe_stream = streams - 1; } } else { if (mapping_family != 255) { return -5; } streams = channels; coupled_streams = 0; for (byte b = 0; b < channels; b++) { mapping[b] = b; } } return opus_multistream_encoder_init(Fs, channels, streams, coupled_streams, mapping, application, (channels > 2 && mapping_family == 1) ? 1 : 0); } [Obsolete("Use OpusCodecFactory methods which can give you native code if supported by your platform")] public static OpusMSEncoder Create(int Fs, int channels, int streams, int coupled_streams, byte[] mapping, OpusApplication application) { if (channels > 255 || channels < 1 || coupled_streams > streams || streams < 1 || coupled_streams < 0 || streams > 255 - coupled_streams) { throw new ArgumentException("Invalid channel / stream configuration"); } OpusMSEncoder opusMSEncoder = new OpusMSEncoder(streams, coupled_streams); int num = opusMSEncoder.opus_multistream_encoder_init(Fs, channels, streams, coupled_streams, mapping, application, 0); return num switch { -1 => throw new ArgumentException("OPUS_BAD_ARG when creating MS encoder"), 0 => opusMSEncoder, _ => throw new OpusException("Could not create MS encoder: " + CodecHelpers.opus_strerror(num), num), }; } internal static void GetStreamCount(int channels, int mapping_family, BoxedValueInt nb_streams, BoxedValueInt nb_coupled_streams) { switch (mapping_family) { case 0: switch (channels) { case 1: nb_streams.Val = 1; nb_coupled_streams.Val = 0; break; case 2: nb_streams.Val = 1; nb_coupled_streams.Val = 1; break; default: throw new ArgumentException("More than 2 channels requires custom mappings"); } return; case 1: if (channels <= 8 && channels >= 1) { nb_streams.Val = VorbisLayout.vorbis_mappings[channels - 1].nb_streams; nb_coupled_streams.Val = VorbisLayout.vorbis_mappings[channels - 1].nb_coupled_streams; return; } break; } if (mapping_family == 255) { nb_streams.Val = channels; nb_coupled_streams.Val = 0; return; } throw new ArgumentException("Invalid mapping family"); } [Obsolete("Use OpusCodecFactory methods which can give you native code if supported by your platform")] public static OpusMSEncoder CreateSurround(int Fs, int channels, int mapping_family, out int streams, out int coupled_streams, byte[] mapping, OpusApplication application) { if (channels > 255 || channels < 1 || application == OpusApplication.OPUS_APPLICATION_UNIMPLEMENTED) { throw new ArgumentException("Invalid channel count or application"); } BoxedValueInt boxedValueInt = new BoxedValueInt(); BoxedValueInt boxedValueInt2 = new BoxedValueInt(); GetStreamCount(channels, mapping_family, boxedValueInt, boxedValueInt2); OpusMSEncoder opusMSEncoder = new OpusMSEncoder(boxedValueInt.Val, boxedValueInt2.Val); int num = opusMSEncoder.opus_multistream_surround_encoder_init(Fs, channels, mapping_family, out streams, out coupled_streams, mapping, application); return num switch { -1 => throw new ArgumentException("Bad argument passed to CreateSurround"), 0 => opusMSEncoder, _ => throw new OpusException("Could not create multistream encoder: " + CodecHelpers.opus_strerror(num), num), }; } internal int surround_rate_allocation(int[] out_rates, int frame_size) { int num = 0; int sampleRate = encoders[0].SampleRate; int num2 = ((bitrate_bps <= layout.nb_channels * 40000) ? (bitrate_bps / layout.nb_channels / 2) : 20000); num2 += 60 * (sampleRate / frame_size - 50); int num3 = 3500 + 60 * (sampleRate / frame_size - 50); int num4 = 512; int num5 = 32; int num6; if (bitrate_bps == -1000) { num6 = sampleRate + 60 * sampleRate / frame_size; } else if (bitrate_bps == -1) { num6 = 300000; } else { int num7 = ((lfe_stream != -1) ? 1 : 0); int nb_coupled_streams = layout.nb_coupled_streams; int num8 = layout.nb_streams - nb_coupled_streams - num7; int num9 = (num8 << 8) + num4 * nb_coupled_streams + num7 * num5; num6 = 256 * (bitrate_bps - num3 * num7 - num2 * (nb_coupled_streams + num8)) / num9; } for (int i = 0; i < layout.nb_streams; i++) { if (i < layout.nb_coupled_streams) { out_rates[i] = num2 + (num6 * num4 >> 8); } else if (i != lfe_stream) { out_rates[i] = num2 + num6; } else { out_rates[i] = num3 + (num6 * num5 >> 8); } out_rates[i] = Inlines.IMAX(out_rates[i], 500); num += out_rates[i]; } return num; } internal int opus_multistream_encode_native(opus_copy_channel_in_func copy_channel_in, ReadOnlySpan pcm, int analysis_frame_size, Span data, int max_data_bytes, int lsb_depth, Downmix.downmix_func downmix, int float_api) { byte[] array = new byte[3832]; OpusRepacketizer opusRepacketizer = new OpusRepacketizer(); int[] array2 = new int[256]; int[] array3 = new int[42]; int[] mem = null; int[] array4 = null; int num = 0; if (surround != 0) { array4 = preemph_mem; mem = window_mem; } int num2 = 0; int sampleRate = encoders[num2].SampleRate; int num3 = (encoders[num2].UseVBR ? 1 : 0); CeltMode celtMode = encoders[num2].GetCeltMode(); int c = layout.nb_streams + layout.nb_coupled_streams; int lookahead = encoders[num2].Lookahead; lookahead -= sampleRate / 400; int num4 = CodecHelpers.compute_frame_size(pcm, analysis_frame_size, variable_duration, c, sampleRate, bitrate_bps, lookahead, downmix, subframe_mem, encoders[num2].analysis.enabled); if (400 * num4 < sampleRate) { return -1; } if (400 * num4 != sampleRate && 200 * num4 != sampleRate && 100 * num4 != sampleRate && 50 * num4 != sampleRate && 25 * num4 != sampleRate && 50 * num4 != 3 * sampleRate) { return -1; } int num5 = layout.nb_streams * 2 - 1; if (max_data_bytes < num5) { return -2; } short[] array5 = new short[2 * num4]; int[] array6 = new int[21 * layout.nb_channels]; if (surround != 0) { surround_analysis(celtMode, pcm, array6, mem, array4, num4, 120, layout.nb_channels, sampleRate, copy_channel_in); } int num6 = surround_rate_allocation(array2, num4); if (num3 == 0) { if (bitrate_bps == -1000) { max_data_bytes = Inlines.IMIN(max_data_bytes, 3 * num6 / (24 * sampleRate / num4)); } else if (bitrate_bps != -1) { max_data_bytes = Inlines.IMIN(max_data_bytes, Inlines.IMAX(num5, 3 * bitrate_bps / (24 * sampleRate / num4))); } } for (int i = 0; i < layout.nb_streams; i++) { OpusEncoder opusEncoder = encoders[num2]; num2++; opusEncoder.Bitrate = array2[i]; if (surround != 0) { int num7 = bitrate_bps; if (num4 * 50 < sampleRate) { num7 -= 60 * (sampleRate / num4 - 50) * layout.nb_channels; } if (num7 > 10000 * layout.nb_channels) { opusEncoder.Bandwidth = OpusBandwidth.OPUS_BANDWIDTH_FULLBAND; } else if (num7 > 7000 * layout.nb_channels) { opusEncoder.Bandwidth = OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND; } else if (num7 > 5000 * layout.nb_channels) { opusEncoder.Bandwidth = OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND; } else { opusEncoder.Bandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND; } if (i < layout.nb_coupled_streams) { opusEncoder.ForceMode = OpusMode.MODE_CELT_ONLY; opusEncoder.ForceChannels = 2; } } } num2 = 0; int num8 = 0; for (int i = 0; i < layout.nb_streams; i++) { opusRepacketizer.Reset(); OpusEncoder opusEncoder2 = encoders[num2]; int c2; int c3; if (i < layout.nb_coupled_streams) { int num9 = OpusMultistream.get_left_channel(layout, i, -1); int num10 = OpusMultistream.get_right_channel(layout, i, -1); copy_channel_in(array5, 0, 2, pcm, layout.nb_channels, num9, num4); copy_channel_in(array5, 1, 2, pcm, layout.nb_channels, num10, num4); num2++; if (surround != 0) { for (int j = 0; j < 21; j++) { array3[j] = array6[21 * num9 + j]; array3[21 + j] = array6[21 * num10 + j]; } } c2 = num9; c3 = num10; } else { int num11 = OpusMultistream.get_mono_channel(layout, i, -1); copy_channel_in(array5, 0, 1, pcm, layout.nb_channels, num11, num4); num2++; if (surround != 0) { for (int k = 0; k < 21; k++) { array3[k] = array6[21 * num11 + k]; } } c2 = num11; c3 = -1; } if (surround != 0) { opusEncoder2.SetEnergyMask(array3); } int num12 = max_data_bytes - num8; num12 -= Inlines.IMAX(0, 2 * (layout.nb_streams - i - 1) - 1); num12 = Inlines.IMIN(num12, 3832); if (i != layout.nb_streams - 1) { num12 -= ((num12 <= 253) ? 1 : 2); } if (num3 == 0 && i == layout.nb_streams - 1) { opusEncoder2.Bitrate = num12 * (8 * sampleRate / num4); } int num13 = opusEncoder2.opus_encode_native(array5, 0, num4, array, 0, num12, lsb_depth, pcm, analysis_frame_size, c2, c3, layout.nb_channels, downmix, float_api); if (num13 < 0) { return num13; } opusRepacketizer.AddPacket(array, 0, num13); num13 = opusRepacketizer.opus_repacketizer_out_range_impl(0, opusRepacketizer.GetNumFrames(), data, num, max_data_bytes - num8, (i != layout.nb_streams - 1) ? 1 : 0, (num3 == 0 && i == layout.nb_streams - 1) ? 1 : 0); num += num13; num8 += num13; } return num8; } internal static void opus_copy_channel_in_float(Span dst, int dst_offset, int dst_stride, ReadOnlySpan src, int src_stride, int src_channel, int frame_size) { for (int i = 0; i < frame_size; i++) { dst[i * dst_stride + dst_offset] = Inlines.FLOAT2INT16(src[i * src_stride + src_channel]); } } internal static void opus_copy_channel_in_short(Span dst, int dst_offset, int dst_stride, ReadOnlySpan src, int src_stride, int src_channel, int frame_size) { for (int i = 0; i < frame_size; i++) { dst[i * dst_stride + dst_offset] = src[i * src_stride + src_channel]; } } [Obsolete("Use Span<> overrides if possible")] public int EncodeMultistream(short[] pcm, int pcm_offset, int frame_size, byte[] outputBuffer, int outputBuffer_offset, int max_data_bytes) { return EncodeMultistream(pcm.AsSpan(pcm_offset), frame_size, outputBuffer.AsSpan(outputBuffer_offset), max_data_bytes); } public int EncodeMultistream(ReadOnlySpan pcm, int frame_size, Span outputBuffer, int max_data_bytes) { int num = opus_multistream_encode_native(opus_copy_channel_in_short, pcm, frame_size, outputBuffer, max_data_bytes, 16, Downmix.downmix_int, 0); if (num < 0) { if (num == -1) { throw new ArgumentException("OPUS_BAD_ARG while encoding"); } throw new OpusException("An error occurred during encoding: " + CodecHelpers.opus_strerror(num), num); } return num; } [Obsolete("Use Span<> overrides if possible")] public int EncodeMultistream(float[] pcm, int pcm_offset, int frame_size, byte[] outputBuffer, int outputBuffer_offset, int max_data_bytes) { return EncodeMultistream(pcm.AsSpan(pcm_offset), frame_size, outputBuffer.AsSpan(outputBuffer_offset), max_data_bytes); } public int EncodeMultistream(ReadOnlySpan pcm, int frame_size, Span outputBuffer, int max_data_bytes) { int num = opus_multistream_encode_native(opus_copy_channel_in_float, pcm, frame_size, outputBuffer, max_data_bytes, 16, Downmix.downmix_float, 1); if (num < 0) { if (num == -1) { throw new ArgumentException("OPUS_BAD_ARG while encoding"); } throw new OpusException("An error occurred during encoding: " + CodecHelpers.opus_strerror(num), num); } return num; } public OpusEncoder GetMultistreamEncoderState(int streamId) { if (streamId >= layout.nb_streams) { throw new ArgumentException("Requested stream doesn't exist"); } return encoders[streamId]; } public string GetVersionString() { return CodecHelpers.GetVersionString(); } public void Dispose() { } } public class OpusPacketInfo { public byte TOCByte { get; private set; } public IList Frames { get; private set; } public int PayloadOffset { get; private set; } public OpusBandwidth Bandwidth { get { OpusBandwidth opusBandwidth; if ((TOCByte & 0x80) == 0) { opusBandwidth = (((TOCByte & 0x60) != 96) ? ((OpusBandwidth)(1101 + ((TOCByte >> 5) & 3))) : (((TOCByte & 0x10u) != 0) ? OpusBandwidth.OPUS_BANDWIDTH_FULLBAND : OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND)); } else { opusBandwidth = (OpusBandwidth)(1102 + ((TOCByte >> 5) & 3)); if (opusBandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) { opusBandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND; } } return opusBandwidth; } } public int NumEncodedChannels { get { if ((TOCByte & 4) == 0) { return 1; } return 2; } } public OpusMode EncoderMode { get { if ((TOCByte & 0x80u) != 0) { return OpusMode.MODE_CELT_ONLY; } if ((TOCByte & 0x60) == 96) { return OpusMode.MODE_HYBRID; } return OpusMode.MODE_SILK_ONLY; } } private OpusPacketInfo(byte toc, IList frames, int payloadOffset) { TOCByte = toc; Frames = frames; PayloadOffset = payloadOffset; } [Obsolete("Use Span<> overrides if possible")] public static OpusPacketInfo ParseOpusPacket(byte[] packet, int packet_offset, int len) { return ParseOpusPacket(packet.AsSpan(packet_offset, len)); } public static OpusPacketInfo ParseOpusPacket(ReadOnlySpan packet) { int numFrames = GetNumFrames(packet); byte[][] array = new byte[numFrames][]; int[] array2 = new int[numFrames]; short[] array3 = new short[numFrames]; byte out_toc; int payload_offset; int packet_offset; int num = opus_packet_parse_impl(packet, 0, packet.Length, 0, out out_toc, array, array2, 0, array3, 0, out payload_offset, out packet_offset); if (num < 0) { throw new OpusException("An error occurred while parsing the packet", num); } IList list = new List(); for (int i = 0; i < numFrames; i++) { byte[] array4 = new byte[array3[i]]; array[i].AsSpan(array2[i], array4.Length).CopyTo(array4); list.Add(array4); } return new OpusPacketInfo(out_toc, list, payload_offset); } public int NumSamplesPerFrame(int Fs) { int num; if ((TOCByte & 0x80u) != 0) { num = (TOCByte >> 3) & 3; return (Fs << num) / 400; } if ((TOCByte & 0x60) == 96) { return ((TOCByte & 8u) != 0) ? (Fs / 50) : (Fs / 100); } num = (TOCByte >> 3) & 3; if (num == 3) { return Fs * 60 / 1000; } return (Fs << num) / 100; } public static int GetNumSamplesPerFrame(ReadOnlySpan packet, int Fs) { int num; if ((packet[0] & 0x80u) != 0) { num = (packet[0] >> 3) & 3; return (Fs << num) / 400; } if ((packet[0] & 0x60) == 96) { return ((packet[0] & 8u) != 0) ? (Fs / 50) : (Fs / 100); } num = (packet[0] >> 3) & 3; if (num == 3) { return Fs * 60 / 1000; } return (Fs << num) / 100; } public static OpusBandwidth GetBandwidth(ReadOnlySpan packet) { OpusBandwidth opusBandwidth; if ((packet[0] & 0x80) == 0) { opusBandwidth = (((packet[0] & 0x60) != 96) ? ((OpusBandwidth)(1101 + ((packet[0] >> 5) & 3))) : (((packet[0] & 0x10u) != 0) ? OpusBandwidth.OPUS_BANDWIDTH_FULLBAND : OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND)); } else { opusBandwidth = (OpusBandwidth)(1102 + ((packet[0] >> 5) & 3)); if (opusBandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) { opusBandwidth = OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND; } } return opusBandwidth; } public static int GetNumEncodedChannels(ReadOnlySpan packet) { if ((packet[0] & 4) == 0) { return 1; } return 2; } public static int GetNumFrames(ReadOnlySpan packet) { if (packet.Length < 1) { return -1; } switch (packet[0] & 3) { case 0: return 1; default: return 2; case 3: if (packet.Length < 2) { return -4; } return packet[1] & 0x3F; } } public static int GetNumSamples(ReadOnlySpan packet, int Fs) { int numFrames = GetNumFrames(packet); if (numFrames < 0) { return numFrames; } int num = numFrames * GetNumSamplesPerFrame(packet, Fs); if (num * 25 > Fs * 3) { return -4; } return num; } [Obsolete("Use Span<> overrides if possible")] public static int GetNumSamples(OpusDecoder dec, byte[] packet, int packet_offset, int len) { return GetNumSamples(packet.AsSpan(packet_offset, len), dec.Fs); } public static int GetNumSamples(OpusDecoder dec, ReadOnlySpan packet) { return GetNumSamples(packet, dec.Fs); } public static OpusMode GetEncoderMode(ReadOnlySpan packet) { if ((packet[0] & 0x80u) != 0) { return OpusMode.MODE_CELT_ONLY; } if ((packet[0] & 0x60) == 96) { return OpusMode.MODE_HYBRID; } return OpusMode.MODE_SILK_ONLY; } internal static int encode_size(int size, Span data, int data_ptr) { if (size < 252) { data[data_ptr] = (byte)size; return 1; } data[data_ptr] = (byte)(252 + (size & 3)); data[data_ptr + 1] = (byte)(size - data[data_ptr] >> 2); return 2; } internal static int parse_size(ReadOnlySpan data, int data_ptr, int len, BoxedValueShort size) { if (len < 1) { size.Val = -1; return -1; } if (data[data_ptr] < 252) { size.Val = data[data_ptr]; return 1; } if (len < 2) { size.Val = -1; return -1; } size.Val = (short)(4 * data[data_ptr + 1] + data[data_ptr]); return 2; } internal static int opus_packet_parse_impl(ReadOnlySpan data, int data_ptr, int len, int self_delimited, out byte out_toc, byte[][] frames, Span frames_ptrs, int frames_ptr, Span sizes, int sizes_ptr, out int payload_offset, out int packet_offset) { int num = 0; int num2 = data_ptr; out_toc = 0; payload_offset = 0; packet_offset = 0; if (sizes.IsEmpty || len < 0) { return -1; } if (len == 0) { return -4; } int numSamplesPerFrame = GetNumSamplesPerFrame(data.Slice(data_ptr), 48000); int num3 = 0; byte b = data[data_ptr++]; len--; int num4 = len; int num5; switch (b & 3) { case 0: num5 = 1; break; case 1: num5 = 2; num3 = 1; if (self_delimited == 0) { if (((uint)len & (true ? 1u : 0u)) != 0) { return -4; } num4 = len / 2; sizes[sizes_ptr] = (short)num4; } break; case 2: { num5 = 2; BoxedValueShort boxedValueShort = new BoxedValueShort(sizes[sizes_ptr]); int num8 = parse_size(data, data_ptr, len, boxedValueShort); sizes[sizes_ptr] = boxedValueShort.Val; len -= num8; if (sizes[sizes_ptr] < 0 || sizes[sizes_ptr] > len) { return -4; } data_ptr += num8; num4 = len - sizes[sizes_ptr]; break; } default: { if (len < 1) { return -4; } byte b2 = data[data_ptr++]; num5 = b2 & 0x3F; if (num5 <= 0 || numSamplesPerFrame * num5 > 5760) { return -4; } len--; if ((b2 & 0x40u) != 0) { int num6; do { if (len <= 0) { return -4; } num6 = data[data_ptr++]; len--; int num7 = ((num6 == 255) ? 254 : num6); len -= num7; num += num7; } while (num6 == 255); } if (len < 0) { return -4; } num3 = (((b2 & 0x80) == 0) ? 1 : 0); if (num3 == 0) { num4 = len; for (int i = 0; i < num5 - 1; i++) { BoxedValueShort boxedValueShort = new BoxedValueShort(sizes[sizes_ptr + i]); int num8 = parse_size(data, data_ptr, len, boxedValueShort); sizes[sizes_ptr + i] = boxedValueShort.Val; len -= num8; if (sizes[sizes_ptr + i] < 0 || sizes[sizes_ptr + i] > len) { return -4; } data_ptr += num8; num4 -= num8 + sizes[sizes_ptr + i]; } if (num4 < 0) { return -4; } } else if (self_delimited == 0) { num4 = len / num5; if (num4 * num5 != len) { return -4; } for (int i = 0; i < num5 - 1; i++) { sizes[sizes_ptr + i] = (short)num4; } } break; } } if (self_delimited != 0) { BoxedValueShort boxedValueShort2 = new BoxedValueShort(sizes[sizes_ptr + num5 - 1]); int num8 = parse_size(data, data_ptr, len, boxedValueShort2); sizes[sizes_ptr + num5 - 1] = boxedValueShort2.Val; len -= num8; if (sizes[sizes_ptr + num5 - 1] < 0 || sizes[sizes_ptr + num5 - 1] > len) { return -4; } data_ptr += num8; if (num3 != 0) { if (sizes[sizes_ptr + num5 - 1] * num5 > len) { return -4; } for (int i = 0; i < num5 - 1; i++) { sizes[sizes_ptr + i] = sizes[sizes_ptr + num5 - 1]; } } else if (num8 + sizes[sizes_ptr + num5 - 1] > num4) { return -4; } } else { if (num4 > 1275) { return -4; } sizes[sizes_ptr + num5 - 1] = (short)num4; } payload_offset = data_ptr - num2; for (int i = 0; i < num5; i++) { if (frames != null) { byte[] array = new byte[data.Length]; data.CopyTo(array.AsSpan()); frames[frames_ptr + i] = array; } if (!frames_ptrs.IsEmpty) { frames_ptrs[frames_ptr + i] = data_ptr; } data_ptr += sizes[sizes_ptr + i]; } packet_offset = num + (data_ptr - num2); out_toc = b; return num5; } } public class OpusRepacketizer { internal byte toc; internal int nb_frames; internal readonly byte[][] frames = new byte[48][]; internal readonly int[] frames_ptrs = new int[48]; internal readonly short[] len = new short[48]; internal int framesize; public void Reset() { nb_frames = 0; } public OpusRepacketizer() { Reset(); } internal int opus_repacketizer_cat_impl(Span data, int data_ptr, int len, int self_delimited) { if (len < 1) { return -4; } if (nb_frames == 0) { toc = data[data_ptr]; framesize = OpusPacketInfo.GetNumSamplesPerFrame(data.Slice(data_ptr), 8000); } else if ((toc & 0xFC) != (data[data_ptr] & 0xFC)) { return -4; } int numFrames = OpusPacketInfo.GetNumFrames(data.Slice(data_ptr, len)); if (numFrames < 1) { return -4; } if ((numFrames + nb_frames) * framesize > 960) { return -4; } byte out_toc; int payload_offset; int num = OpusPacketInfo.opus_packet_parse_impl(data, data_ptr, len, self_delimited, out out_toc, frames, frames_ptrs, nb_frames, this.len, nb_frames, out payload_offset, out payload_offset); if (num < 1) { return num; } nb_frames += numFrames; return 0; } public int AddPacket(Span data, int data_offset, int len) { return opus_repacketizer_cat_impl(data, data_offset, len, 0); } public int GetNumFrames() { return nb_frames; } internal int opus_repacketizer_out_range_impl(int begin, int end, Span data, int data_ptr, int maxlen, int self_delimited, int pad) { if (begin < 0 || begin >= end || end > nb_frames) { return -1; } int num = end - begin; int num2 = ((self_delimited != 0) ? (1 + ((len[num - 1] >= 252) ? 1 : 0)) : 0); int num3 = data_ptr; switch (num) { case 1: num2 += len[0] + 1; if (num2 > maxlen) { return -2; } data[num3++] = (byte)(toc & 0xFCu); break; case 2: if (len[1] == len[0]) { num2 += 2 * len[0] + 1; if (num2 > maxlen) { return -2; } data[num3++] = (byte)((toc & 0xFCu) | 1u); break; } num2 += len[0] + len[1] + 2 + ((len[0] >= 252) ? 1 : 0); if (num2 > maxlen) { return -2; } data[num3++] = (byte)((toc & 0xFCu) | 2u); num3 += OpusPacketInfo.encode_size(len[0], data, num3); break; } if (num > 2 || (pad != 0 && num2 < maxlen)) { int num4 = 0; num3 = data_ptr; num2 = ((self_delimited != 0) ? (1 + ((len[num - 1] >= 252) ? 1 : 0)) : 0); int num5 = 0; for (int i = 1; i < num; i++) { if (len[i] != len[0]) { num5 = 1; break; } } if (num5 != 0) { num2 += 2; for (int i = 0; i < num - 1; i++) { num2 += 1 + ((len[i] >= 252) ? 1 : 0) + len[i]; } num2 += len[num - 1]; if (num2 > maxlen) { return -2; } data[num3++] = (byte)((toc & 0xFCu) | 3u); data[num3++] = (byte)((uint)num | 0x80u); } else { num2 += num * len[0] + 2; if (num2 > maxlen) { return -2; } data[num3++] = (byte)((toc & 0xFCu) | 3u); data[num3++] = (byte)num; } num4 = ((pad != 0) ? (maxlen - num2) : 0); if (num4 != 0) { data[data_ptr + 1] |= 64; int num6 = (num4 - 1) / 255; for (int i = 0; i < num6; i++) { data[num3++] = byte.MaxValue; } data[num3++] = (byte)(num4 - 255 * num6 - 1); num2 += num4; } if (num5 != 0) { for (int i = 0; i < num - 1; i++) { num3 += OpusPacketInfo.encode_size(len[i], data, num3); } } } if (self_delimited != 0) { int num7 = OpusPacketInfo.encode_size(len[num - 1], data, num3); num3 += num7; } for (int i = begin; i < num + begin; i++) { frames[i].AsSpan(frames_ptrs[i], len[i]).CopyTo(data.Slice(num3)); num3 += len[i]; } if (pad != 0) { while (num3 < data_ptr + maxlen) { data[num3++] = 0; } } return num2; } public int CreatePacket(int begin, int end, byte[] data, int data_offset, int maxlen) { return opus_repacketizer_out_range_impl(begin, end, data, data_offset, maxlen, 0, 0); } public int CreatePacket(byte[] data, int data_offset, int maxlen) { return opus_repacketizer_out_range_impl(0, nb_frames, data, data_offset, maxlen, 0, 0); } public static int PadPacket(Span data, int data_offset, int len, int new_len) { OpusRepacketizer opusRepacketizer = new OpusRepacketizer(); if (len < 1) { return -1; } if (len == new_len) { return 0; } if (len > new_len) { return -1; } opusRepacketizer.Reset(); Arrays.MemMoveByte(data, data_offset, data_offset + new_len - len, len); opusRepacketizer.AddPacket(data, data_offset + new_len - len, len); int num = opusRepacketizer.opus_repacketizer_out_range_impl(0, opusRepacketizer.nb_frames, data, data_offset, new_len, 0, 1); if (num > 0) { return 0; } return num; } public static int UnpadPacket(byte[] data, int data_offset, int len) { if (len < 1) { return -1; } OpusRepacketizer opusRepacketizer = new OpusRepacketizer(); opusRepacketizer.Reset(); int num = opusRepacketizer.AddPacket(data, data_offset, len); if (num < 0) { return num; } return opusRepacketizer.opus_repacketizer_out_range_impl(0, opusRepacketizer.nb_frames, data, data_offset, len, 0, 0); } public static int PadMultistreamPacket(byte[] data, int data_offset, int len, int new_len, int nb_streams) { short[] array = new short[48]; if (len < 1) { return -1; } if (len == new_len) { return 0; } if (len > new_len) { return -1; } int num = new_len - len; for (int i = 0; i < nb_streams - 1; i++) { if (len <= 0) { return -4; } byte out_toc; int payload_offset; int packet_offset; int num2 = OpusPacketInfo.opus_packet_parse_impl(data, data_offset, len, 1, out out_toc, null, null, 0, array, 0, out payload_offset, out packet_offset); if (num2 < 0) { return num2; } data_offset += packet_offset; len -= packet_offset; } return PadPacket(data, data_offset, len, len + num); } public static int UnpadMultistreamPacket(byte[] data, int data_offset, int len, int nb_streams) { short[] array = new short[48]; OpusRepacketizer opusRepacketizer = new OpusRepacketizer(); if (len < 1) { return -1; } int num = data_offset; int num2 = 0; for (int i = 0; i < nb_streams; i++) { int self_delimited = ((i != nb_streams) ? 1 : 0) - 1; if (len <= 0) { return -4; } opusRepacketizer.Reset(); int num3 = OpusPacketInfo.opus_packet_parse_impl(data, data_offset, len, self_delimited, out var _, null, null, 0, array, 0, out var _, out var packet_offset); if (num3 < 0) { return num3; } num3 = opusRepacketizer.opus_repacketizer_cat_impl(data, data_offset, packet_offset, self_delimited); if (num3 < 0) { return num3; } num3 = opusRepacketizer.opus_repacketizer_out_range_impl(0, opusRepacketizer.nb_frames, data, num, len, self_delimited, 0); if (num3 < 0) { return num3; } num2 += num3; num += num3; data_offset += packet_offset; len -= packet_offset; } return num2; } } internal class StereoWidthState { internal int XX; internal int XY; internal int YY; internal int smoothed_width; internal int max_follower; internal void Reset() { XX = 0; XY = 0; YY = 0; smoothed_width = 0; max_follower = 0; } } internal class TonalityAnalysisState { internal bool enabled; internal readonly float[] angle = new float[240]; internal readonly float[] d_angle = new float[240]; internal readonly float[] d2_angle = new float[240]; internal readonly int[] inmem = new int[720]; internal int mem_fill; internal readonly float[] prev_band_tonality = new float[18]; internal float prev_tonality; internal readonly float[][] E = Arrays.InitTwoDimensionalArray(8, 18); internal readonly float[] lowE = new float[18]; internal readonly float[] highE = new float[18]; internal readonly float[] meanE = new float[21]; internal readonly float[] mem = new float[32]; internal readonly float[] cmean = new float[8]; internal readonly float[] std = new float[9]; internal float music_prob; internal float Etracker; internal float lowECount; internal int E_count; internal int last_music; internal int last_transition; internal int count; internal readonly float[] subframe_mem = new float[3]; internal int analysis_offset; internal readonly float[] pspeech = new float[200]; internal readonly float[] pmusic = new float[200]; internal float speech_confidence; internal float music_confidence; internal int speech_confidence_count; internal int music_confidence_count; internal int write_pos; internal int read_pos; internal int read_subframe; internal readonly AnalysisInfo[] info = new AnalysisInfo[200]; internal TonalityAnalysisState() { for (int i = 0; i < 200; i++) { info[i] = new AnalysisInfo(); } } internal void Reset() { Arrays.MemSetFloat(angle, 0f, 240); Arrays.MemSetFloat(d_angle, 0f, 240); Arrays.MemSetFloat(d2_angle, 0f, 240); Arrays.MemSetInt(inmem, 0, 720); mem_fill = 0; Arrays.MemSetFloat(prev_band_tonality, 0f, 18); prev_tonality = 0f; for (int i = 0; i < 8; i++) { Arrays.MemSetFloat(E[i], 0f, 18); } Arrays.MemSetFloat(lowE, 0f, 18); Arrays.MemSetFloat(highE, 0f, 18); Arrays.MemSetFloat(meanE, 0f, 21); Arrays.MemSetFloat(mem, 0f, 32); Arrays.MemSetFloat(cmean, 0f, 8); Arrays.MemSetFloat(std, 0f, 9); music_prob = 0f; Etracker = 0f; lowECount = 0f; E_count = 0; last_music = 0; last_transition = 0; count = 0; Arrays.MemSetFloat(subframe_mem, 0f, 3); analysis_offset = 0; Arrays.MemSetFloat(pspeech, 0f, 200); Arrays.MemSetFloat(pmusic, 0f, 200); speech_confidence = 0f; music_confidence = 0f; speech_confidence_count = 0; music_confidence_count = 0; write_pos = 0; read_pos = 0; read_subframe = 0; for (int j = 0; j < 200; j++) { info[j].Reset(); } } } internal class VorbisLayout { internal int nb_streams; internal int nb_coupled_streams; internal byte[] mapping; internal static readonly VorbisLayout[] vorbis_mappings = new VorbisLayout[8] { new VorbisLayout(1, 0, new byte[1]), new VorbisLayout(1, 1, new byte[2] { 0, 1 }), new VorbisLayout(2, 1, new byte[3] { 0, 2, 1 }), new VorbisLayout(2, 2, new byte[4] { 0, 1, 2, 3 }), new VorbisLayout(3, 2, new byte[5] { 0, 4, 1, 2, 3 }), new VorbisLayout(4, 2, new byte[6] { 0, 4, 1, 2, 3, 5 }), new VorbisLayout(4, 3, new byte[7] { 0, 4, 1, 2, 3, 5, 6 }), new VorbisLayout(5, 3, new byte[8] { 0, 6, 1, 2, 3, 4, 5, 7 }) }; internal VorbisLayout(int streams, int coupled_streams, byte[] map) { nb_streams = streams; nb_coupled_streams = coupled_streams; mapping = map; } } } namespace Concentus.Enums { public enum OpusApplication { OPUS_APPLICATION_UNIMPLEMENTED = 0, OPUS_APPLICATION_VOIP = 2048, OPUS_APPLICATION_AUDIO = 2049, OPUS_APPLICATION_RESTRICTED_LOWDELAY = 2051 } public enum OpusBandwidth { OPUS_BANDWIDTH_AUTO = -1000, OPUS_BANDWIDTH_NARROWBAND = 1101, OPUS_BANDWIDTH_MEDIUMBAND = 1102, OPUS_BANDWIDTH_WIDEBAND = 1103, OPUS_BANDWIDTH_SUPERWIDEBAND = 1104, OPUS_BANDWIDTH_FULLBAND = 1105 } internal static class OpusBandwidthHelpers { public static int GetOrdinal(OpusBandwidth bw) { return (int)(bw - 1101); } public static OpusBandwidth MIN(OpusBandwidth a, OpusBandwidth b) { if (a < b) { return a; } return b; } public static OpusBandwidth MAX(OpusBandwidth a, OpusBandwidth b) { if (a > b) { return a; } return b; } } internal static class OpusControl { internal const int OPUS_SET_APPLICATION_REQUEST = 4000; internal const int OPUS_GET_APPLICATION_REQUEST = 4001; internal const int OPUS_SET_BITRATE_REQUEST = 4002; internal const int OPUS_GET_BITRATE_REQUEST = 4003; internal const int OPUS_SET_MAX_BANDWIDTH_REQUEST = 4004; internal const int OPUS_GET_MAX_BANDWIDTH_REQUEST = 4005; internal const int OPUS_SET_VBR_REQUEST = 4006; internal const int OPUS_GET_VBR_REQUEST = 4007; internal const int OPUS_SET_BANDWIDTH_REQUEST = 4008; internal const int OPUS_GET_BANDWIDTH_REQUEST = 4009; internal const int OPUS_SET_COMPLEXITY_REQUEST = 4010; internal const int OPUS_GET_COMPLEXITY_REQUEST = 4011; internal const int OPUS_SET_INBAND_FEC_REQUEST = 4012; internal const int OPUS_GET_INBAND_FEC_REQUEST = 4013; internal const int OPUS_SET_PACKET_LOSS_PERC_REQUEST = 4014; internal const int OPUS_GET_PACKET_LOSS_PERC_REQUEST = 4015; internal const int OPUS_SET_DTX_REQUEST = 4016; internal const int OPUS_GET_DTX_REQUEST = 4017; internal const int OPUS_SET_VBR_CONSTRAINT_REQUEST = 4020; internal const int OPUS_GET_VBR_CONSTRAINT_REQUEST = 4021; internal const int OPUS_SET_FORCE_CHANNELS_REQUEST = 4022; internal const int OPUS_GET_FORCE_CHANNELS_REQUEST = 4023; internal const int OPUS_SET_SIGNAL_REQUEST = 4024; internal const int OPUS_GET_SIGNAL_REQUEST = 4025; internal const int OPUS_GET_LOOKAHEAD_REQUEST = 4027; internal const int OPUS_GET_SAMPLE_RATE_REQUEST = 4029; internal const int OPUS_GET_FINAL_RANGE_REQUEST = 4031; internal const int OPUS_GET_PITCH_REQUEST = 4033; internal const int OPUS_SET_GAIN_REQUEST = 4034; internal const int OPUS_GET_GAIN_REQUEST = 4045; internal const int OPUS_SET_LSB_DEPTH_REQUEST = 4036; internal const int OPUS_GET_LSB_DEPTH_REQUEST = 4037; internal const int OPUS_GET_LAST_PACKET_DURATION_REQUEST = 4039; internal const int OPUS_SET_EXPERT_FRAME_DURATION_REQUEST = 4040; internal const int OPUS_GET_EXPERT_FRAME_DURATION_REQUEST = 4041; internal const int OPUS_SET_PREDICTION_DISABLED_REQUEST = 4042; internal const int OPUS_GET_PREDICTION_DISABLED_REQUEST = 4043; internal const int OPUS_RESET_STATE = 4028; internal const int OPUS_SET_VOICE_RATIO_REQUEST = 11018; internal const int OPUS_GET_VOICE_RATIO_REQUEST = 11019; internal const int OPUS_SET_FORCE_MODE_REQUEST = 11002; } public static class OpusError { public const int OPUS_OK = 0; public const int OPUS_BAD_ARG = -1; public const int OPUS_BUFFER_TOO_SMALL = -2; public const int OPUS_INTERNAL_ERROR = -3; public const int OPUS_INVALID_PACKET = -4; public const int OPUS_UNIMPLEMENTED = -5; public const int OPUS_INVALID_STATE = -6; public const int OPUS_ALLOC_FAIL = -7; public const int CONCENTUS_UNKNOWN_ERROR = -100; } public enum OpusFramesize { OPUS_FRAMESIZE_ARG = 5000, OPUS_FRAMESIZE_2_5_MS = 5001, OPUS_FRAMESIZE_5_MS = 5002, OPUS_FRAMESIZE_10_MS = 5003, OPUS_FRAMESIZE_20_MS = 5004, OPUS_FRAMESIZE_40_MS = 5005, OPUS_FRAMESIZE_60_MS = 5006, OPUS_FRAMESIZE_VARIABLE = 5010 } public enum OpusMode { MODE_AUTO = -1000, MODE_SILK_ONLY = 1000, MODE_HYBRID = 1001, MODE_CELT_ONLY = 1002 } public enum OpusSignal { OPUS_SIGNAL_AUTO = -1000, OPUS_SIGNAL_VOICE = 3001, OPUS_SIGNAL_MUSIC = 3002 } } namespace Concentus.Native { internal class KernelInteropLinux { private interface ILibDl { IntPtr DLOpen(string fileName, int flags); int DLClose(IntPtr handle); IntPtr DLError(); } private class LibDL : ILibDl { public IntPtr DLOpen(string fileName, int flags) { return dlopen(fileName, flags); } public int DLClose(IntPtr handle) { return dlclose(handle); } public IntPtr DLError() { return dlerror(); } [DllImport("libdl.so")] private static extern IntPtr dlopen(string fileName, int flags); [DllImport("libdl.so")] private static extern int dlclose(IntPtr handle); [DllImport("libdl.so")] private static extern IntPtr dlerror(); } private class LibDL2 : ILibDl { public IntPtr DLOpen(string fileName, int flags) { return dlopen(fileName, flags); } public int DLClose(IntPtr handle) { return dlclose(handle); } public IntPtr DLError() { return dlerror(); } [DllImport("libdl.so.2")] private static extern IntPtr dlopen(string fileName, int flags); [DllImport("libdl.so.2")] private static extern int dlclose(IntPtr handle); [DllImport("libdl.so.2")] private static extern IntPtr dlerror(); } internal const int RTLD_NOW = 2; private static Lazy _libDlImpl = new Lazy(GetLibDL, LazyThreadSafetyMode.ExecutionAndPublication); internal static readonly IReadOnlyDictionary POSSIBLE_UNIX_MACHINES = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "amd64", PlatformArchitecture.X64 }, { "x86_64", PlatformArchitecture.X64 }, { "i686-64", PlatformArchitecture.X64 }, { "x86", PlatformArchitecture.I386 }, { "i686", PlatformArchitecture.I386 }, { "i686-AT386", PlatformArchitecture.I386 }, { "i386", PlatformArchitecture.I386 }, { "x86pc", PlatformArchitecture.I386 }, { "i86pc", PlatformArchitecture.I386 }, { "armv6l", PlatformArchitecture.ArmV6 }, { "armv7l", PlatformArchitecture.ArmV7 }, { "arm64", PlatformArchitecture.Arm64 }, { "aarch64", PlatformArchitecture.Arm64 }, { "aarch64_be", PlatformArchitecture.Arm64 }, { "armv8l", PlatformArchitecture.Arm64 }, { "armv8b", PlatformArchitecture.Arm64 }, { "mips64", PlatformArchitecture.Mips64 }, { "ppc64", PlatformArchitecture.PowerPC64 }, { "ppc64le", PlatformArchitecture.PowerPC64 } }; private static ILibDl GetLibDL() { try { LibDL libDL = new LibDL(); libDL.DLError(); return libDL; } catch (Exception) { return new LibDL2(); } } public static IntPtr dlopen(string fileName, int flags) { return _libDlImpl.Value.DLOpen(fileName, flags); } public static int dlclose(IntPtr handle) { return _libDlImpl.Value.DLClose(handle); } public static IntPtr dlerror() { return _libDlImpl.Value.DLError(); } internal static PlatformArchitecture? TryGetArchForUnix(TextWriter logger) { try { logger?.WriteLine("Running uname to determine system info..."); using Process process = Process.Start(new ProcessStartInfo { FileName = "uname", Arguments = "-m", UseShellExecute = false, RedirectStandardOutput = true, CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden }); using StreamReader streamReader = process.StandardOutput; string text = streamReader.ReadToEnd(); if (string.IsNullOrEmpty(text)) { return null; } text = text.Trim(); if (POSSIBLE_UNIX_MACHINES.TryGetValue(text, out var value)) { logger?.WriteLine("Got architecture from uname: " + text); return value; } } catch (Exception value2) { logger?.WriteLine(value2); } return null; } } internal class KernelInteropMacOS { internal const int RTLD_NOW = 2; [DllImport("libSystem.dylib")] internal static extern IntPtr dlopen(string fileName, int flags); [DllImport("libSystem.dylib")] internal static extern int dlclose(IntPtr handle); [DllImport("libSystem.dylib")] internal static extern IntPtr dlerror(); } internal class KernelInteropWindows { internal struct SYSTEM_INFO { internal ushort wProcessorArchitecture; internal ushort wReserved; internal uint dwPageSize; internal IntPtr lpMinimumApplicationAddress; internal IntPtr lpMaximumApplicationAddress; internal IntPtr dwActiveProcessorMask; internal uint dwNumberOfProcessors; internal uint dwProcessorType; internal uint dwAllocationGranularity; internal ushort wProcessorLevel; internal ushort wProcessorRevision; } internal const uint LOAD_LIBRARY_AS_DATAFILE = 2u; internal const uint LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 4096u; internal const ushort PROCESSOR_ARCHITECTURE_INTEL = 0; internal const ushort PROCESSOR_ARCHITECTURE_AMD64 = 9; internal const ushort PROCESSOR_ARCHITECTURE_ARM = 5; internal const ushort PROCESSOR_ARCHITECTURE_ARM64 = 18; internal const ushort PROCESSOR_ARCHITECTURE_IA64 = 6; internal const ushort PROCESSOR_ARCHITECTURE_UNKNOWN = ushort.MaxValue; [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] internal static extern IntPtr LoadLibraryExW(string lpFileName, IntPtr hFile, uint dwFlags); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool FreeLibrary(IntPtr hModule); [DllImport("kernel32.dll")] internal static extern uint GetLastError(); [DllImport("kernel32.dll", SetLastError = true)] internal static extern void GetSystemInfo(ref SYSTEM_INFO Info); } internal enum NativeLibraryStatus { Unknown, Available, Unavailable } internal class NativeOpus { private const string LIBRARY_NAME = "opus"; internal const int OPUS_SET_APPLICATION_REQUEST = 4000; internal const int OPUS_GET_APPLICATION_REQUEST = 4001; internal const int OPUS_SET_BITRATE_REQUEST = 4002; internal const int OPUS_GET_BITRATE_REQUEST = 4003; internal const int OPUS_SET_MAX_BANDWIDTH_REQUEST = 4004; internal const int OPUS_GET_MAX_BANDWIDTH_REQUEST = 4005; internal const int OPUS_SET_VBR_REQUEST = 4006; internal const int OPUS_GET_VBR_REQUEST = 4007; internal const int OPUS_SET_BANDWIDTH_REQUEST = 4008; internal const int OPUS_GET_BANDWIDTH_REQUEST = 4009; internal const int OPUS_SET_COMPLEXITY_REQUEST = 4010; internal const int OPUS_GET_COMPLEXITY_REQUEST = 4011; internal const int OPUS_SET_INBAND_FEC_REQUEST = 4012; internal const int OPUS_GET_INBAND_FEC_REQUEST = 4013; internal const int OPUS_SET_PACKET_LOSS_PERC_REQUEST = 4014; internal const int OPUS_GET_PACKET_LOSS_PERC_REQUEST = 4015; internal const int OPUS_SET_DTX_REQUEST = 4016; internal const int OPUS_GET_DTX_REQUEST = 4017; internal const int OPUS_SET_VBR_CONSTRAINT_REQUEST = 4020; internal const int OPUS_GET_VBR_CONSTRAINT_REQUEST = 4021; internal const int OPUS_SET_FORCE_CHANNELS_REQUEST = 4022; internal const int OPUS_GET_FORCE_CHANNELS_REQUEST = 4023; internal const int OPUS_SET_SIGNAL_REQUEST = 4024; internal const int OPUS_GET_SIGNAL_REQUEST = 4025; internal const int OPUS_GET_LOOKAHEAD_REQUEST = 4027; internal const int OPUS_GET_SAMPLE_RATE_REQUEST = 4029; internal const int OPUS_GET_FINAL_RANGE_REQUEST = 4031; internal const int OPUS_GET_PITCH_REQUEST = 4033; internal const int OPUS_SET_GAIN_REQUEST = 4034; internal const int OPUS_GET_GAIN_REQUEST = 4045; internal const int OPUS_SET_LSB_DEPTH_REQUEST = 4036; internal const int OPUS_GET_LSB_DEPTH_REQUEST = 4037; internal const int OPUS_GET_LAST_PACKET_DURATION_REQUEST = 4039; internal const int OPUS_SET_EXPERT_FRAME_DURATION_REQUEST = 4040; internal const int OPUS_GET_EXPERT_FRAME_DURATION_REQUEST = 4041; internal const int OPUS_SET_PREDICTION_DISABLED_REQUEST = 4042; internal const int OPUS_GET_PREDICTION_DISABLED_REQUEST = 4043; internal const int OPUS_SET_FORCE_MODE_REQUEST = 11002; internal const int OPUS_RESET_STATE = 4028; internal static bool Initialize(TextWriter logger) { if (NativePlatformUtils.PrepareNativeLibrary("opus", logger) == NativeLibraryStatus.Available) { return opus_get_version_string() != IntPtr.Zero; } return false; } [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal static extern NativeOpusDecoder opus_decoder_create(int Fs, int channels, out int error); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal unsafe static extern NativeOpusMultistreamDecoder opus_multistream_decoder_create(int Fs, int channels, int streams, int coupled_streams, byte* mapping, out int error); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal unsafe static extern int opus_decode(NativeOpusDecoder st, byte* data, int len, short* pcm, int frame_size, int decode_fec); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal unsafe static extern int opus_decode_float(NativeOpusDecoder st, byte* data, int len, float* pcm, int frame_size, int decode_fec); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal unsafe static extern int opus_multistream_decode(NativeOpusMultistreamDecoder st, byte* data, int len, short* pcm, int frame_size, int decode_fec); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal unsafe static extern int opus_multistream_decode_float(NativeOpusMultistreamDecoder st, byte* data, int len, float* pcm, int frame_size, int decode_fec); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal static extern NativeOpusEncoder opus_encoder_create(int Fs, int channels, int application, out int error); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal unsafe static extern NativeOpusMultistreamEncoder opus_multistream_surround_encoder_create(int Fs, int channels, int mapping_family, out int streams, out int coupled_streams, byte* mapping, int application, out int error); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal unsafe static extern int opus_encode(NativeOpusEncoder st, short* pcm, int frame_size, byte* data, int max_data_bytes); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal unsafe static extern int opus_encode_float(NativeOpusEncoder st, float* pcm, int frame_size, byte* data, int max_data_bytes); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal unsafe static extern int opus_multistream_encode(NativeOpusMultistreamEncoder st, short* pcm, int frame_size, byte* data, int max_data_bytes); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal unsafe static extern int opus_multistream_encode_float(NativeOpusMultistreamEncoder st, float* pcm, int frame_size, byte* data, int max_data_bytes); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal static extern int opus_decoder_ctl(NativeOpusDecoder st, int request, int value); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal static extern int opus_decoder_ctl(NativeOpusDecoder st, int request, out int value); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal static extern int opus_encoder_ctl(NativeOpusEncoder st, int request, int value); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal static extern int opus_encoder_ctl(NativeOpusEncoder st, int request, out int value); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal static extern int opus_multistream_decoder_ctl(NativeOpusMultistreamDecoder st, int request, int value); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal static extern int opus_multistream_decoder_ctl(NativeOpusMultistreamDecoder st, int request, out int value); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal static extern int opus_multistream_encoder_ctl(NativeOpusMultistreamEncoder st, int request, int value); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal static extern int opus_multistream_encoder_ctl(NativeOpusMultistreamEncoder st, int request, out int value); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr opus_get_version_string(); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal static extern void opus_encoder_destroy(IntPtr encoder); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal static extern void opus_multistream_encoder_destroy(IntPtr encoder); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal static extern void opus_decoder_destroy(IntPtr decoder); [DllImport("opus", CallingConvention = CallingConvention.Cdecl)] internal static extern void opus_multistream_decoder_destroy(IntPtr decoder); } internal class NativeOpusDecoder : SafeHandleZeroOrMinusOneIsInvalid, IOpusDecoder, IDisposable { private int _sampleRate; private int _numChannels; private NativeOpusDecoder NativeHandle => this; public int SampleRate => _sampleRate; public int NumChannels => _numChannels; public OpusBandwidth Bandwidth { get { NativeOpus.opus_decoder_ctl(NativeHandle, 4009, out var value); return (OpusBandwidth)value; } } public uint FinalRange { get { NativeOpus.opus_decoder_ctl(NativeHandle, 4031, out var value); return (uint)value; } } public int Gain { get { NativeOpus.opus_decoder_ctl(NativeHandle, 4045, out var value); return value; } set { NativeOpus.opus_decoder_ctl(NativeHandle, 4034, value); } } public int LastPacketDuration { get { NativeOpus.opus_decoder_ctl(NativeHandle, 4039, out var value); return value; } } public int Pitch { get { NativeOpus.opus_decoder_ctl(NativeHandle, 4033, out var value); return value; } } internal NativeOpusDecoder() : base(ownsHandle: true) { } protected override bool ReleaseHandle() { NativeOpus.opus_encoder_destroy(handle); return true; } public static NativeOpusDecoder Create(int sampleRate, int channelCount) { int error; NativeOpusDecoder nativeOpusDecoder = NativeOpus.opus_decoder_create(sampleRate, channelCount, out error); if (error != 0) { nativeOpusDecoder.Dispose(); throw new Exception($"Failed to create opus decoder: error {error}"); } nativeOpusDecoder._sampleRate = sampleRate; nativeOpusDecoder._numChannels = channelCount; return nativeOpusDecoder; } public unsafe int Decode(ReadOnlySpan in_data, Span out_pcm, int frame_size, bool decode_fec = false) { fixed (float* pcm = out_pcm) { if (in_data.Length == 0) { return NativeOpus.opus_decode_float(NativeHandle, null, 0, pcm, frame_size, decode_fec ? 1 : 0); } fixed (byte* data = in_data) { return NativeOpus.opus_decode_float(NativeHandle, data, in_data.Length, pcm, frame_size, decode_fec ? 1 : 0); } } } public unsafe int Decode(ReadOnlySpan in_data, Span out_pcm, int frame_size, bool decode_fec = false) { fixed (short* pcm = out_pcm) { if (in_data.Length == 0) { return NativeOpus.opus_decode(NativeHandle, null, 0, pcm, frame_size, decode_fec ? 1 : 0); } fixed (byte* data = in_data) { return NativeOpus.opus_decode(NativeHandle, data, in_data.Length, pcm, frame_size, decode_fec ? 1 : 0); } } } public void ResetState() { NativeOpus.opus_decoder_ctl(NativeHandle, 4028, 0); } public string GetVersionString() { return Marshal.PtrToStringAnsi(NativeOpus.opus_get_version_string()); } } internal class NativeOpusEncoder : SafeHandleZeroOrMinusOneIsInvalid, IOpusEncoder, IDisposable { private int _sampleRate; private int _numChannels; private NativeOpusEncoder NativeHandle => this; public int SampleRate => _sampleRate; public int NumChannels => _numChannels; public int Complexity { get { NativeOpus.opus_encoder_ctl(NativeHandle, 4011, out var value); return value; } set { NativeOpus.opus_encoder_ctl(NativeHandle, 4010, value); } } public bool UseDTX { get { NativeOpus.opus_encoder_ctl(NativeHandle, 4017, out var value); return value != 0; } set { NativeOpus.opus_encoder_ctl(NativeHandle, 4016, value ? 1 : 0); } } public int Bitrate { get { NativeOpus.opus_encoder_ctl(NativeHandle, 4003, out var value); return value; } set { NativeOpus.opus_encoder_ctl(NativeHandle, 4002, value); } } public OpusMode ForceMode { set { NativeOpus.opus_encoder_ctl(NativeHandle, 11002, (int)value); } } public bool UseVBR { get { NativeOpus.opus_encoder_ctl(NativeHandle, 4007, out var value); return value != 0; } set { NativeOpus.opus_encoder_ctl(NativeHandle, 4006, value ? 1 : 0); } } public OpusApplication Application { get { NativeOpus.opus_encoder_ctl(NativeHandle, 4001, out var value); return (OpusApplication)value; } set { NativeOpus.opus_encoder_ctl(NativeHandle, 4000, (int)value); } } public int ForceChannels { get { NativeOpus.opus_encoder_ctl(NativeHandle, 4023, out var value); return value; } set { NativeOpus.opus_encoder_ctl(NativeHandle, 4022, value); } } public OpusBandwidth MaxBandwidth { get { NativeOpus.opus_encoder_ctl(NativeHandle, 4005, out var value); return (OpusBandwidth)value; } set { NativeOpus.opus_encoder_ctl(NativeHandle, 4004, (int)value); } } public OpusBandwidth Bandwidth { get { NativeOpus.opus_encoder_ctl(NativeHandle, 4009, out var value); return (OpusBandwidth)value; } set { NativeOpus.opus_encoder_ctl(NativeHandle, 4008, (int)value); } } public bool UseInbandFEC { get { NativeOpus.opus_encoder_ctl(NativeHandle, 4013, out var value); return value != 0; } set { NativeOpus.opus_encoder_ctl(NativeHandle, 4012, value ? 1 : 0); } } public int PacketLossPercent { get { NativeOpus.opus_encoder_ctl(NativeHandle, 4015, out var value); return value; } set { NativeOpus.opus_encoder_ctl(NativeHandle, 4014, value); } } public bool UseConstrainedVBR { get { NativeOpus.opus_encoder_ctl(NativeHandle, 4021, out var value); return value != 0; } set { NativeOpus.opus_encoder_ctl(NativeHandle, 4020, value ? 1 : 0); } } public OpusSignal SignalType { get { NativeOpus.opus_encoder_ctl(NativeHandle, 4025, out var value); return (OpusSignal)value; } set { NativeOpus.opus_encoder_ctl(NativeHandle, 4024, (int)value); } } public int Lookahead { get { NativeOpus.opus_encoder_ctl(NativeHandle, 4027, out var value); return value; } } public uint FinalRange { get { NativeOpus.opus_encoder_ctl(NativeHandle, 4031, out var value); return (uint)value; } } public int LSBDepth { get { NativeOpus.opus_encoder_ctl(NativeHandle, 4037, out var value); return value; } set { NativeOpus.opus_encoder_ctl(NativeHandle, 4036, value); } } public OpusFramesize ExpertFrameDuration { get { NativeOpus.opus_encoder_ctl(NativeHandle, 4041, out var value); return (OpusFramesize)value; } set { NativeOpus.opus_encoder_ctl(NativeHandle, 4040, (int)value); } } public bool PredictionDisabled { get { NativeOpus.opus_encoder_ctl(NativeHandle, 4043, out var value); return value != 0; } set { NativeOpus.opus_encoder_ctl(NativeHandle, 4042, value ? 1 : 0); } } internal NativeOpusEncoder() : base(ownsHandle: true) { } protected override bool ReleaseHandle() { NativeOpus.opus_encoder_destroy(handle); return true; } public static NativeOpusEncoder Create(int sampleRate, int channelCount, OpusApplication application) { int error; NativeOpusEncoder nativeOpusEncoder = NativeOpus.opus_encoder_create(sampleRate, channelCount, (int)application, out error); if (error != 0) { nativeOpusEncoder.Dispose(); throw new Exception($"Failed to create opus encoder: error {error}"); } nativeOpusEncoder._sampleRate = sampleRate; nativeOpusEncoder._numChannels = channelCount; return nativeOpusEncoder; } public unsafe int Encode(ReadOnlySpan in_pcm, int frame_size, Span out_data, int max_data_bytes) { fixed (short* pcm = in_pcm) { fixed (byte* data = out_data) { return NativeOpus.opus_encode(NativeHandle, pcm, frame_size, data, max_data_bytes); } } } public unsafe int Encode(ReadOnlySpan in_pcm, int frame_size, Span out_data, int max_data_bytes) { fixed (float* pcm = in_pcm) { fixed (byte* data = out_data) { return NativeOpus.opus_encode_float(NativeHandle, pcm, frame_size, data, max_data_bytes); } } } public void ResetState() { NativeOpus.opus_encoder_ctl(NativeHandle, 4028, 0); } public string GetVersionString() { return Marshal.PtrToStringAnsi(NativeOpus.opus_get_version_string()); } } internal class NativeOpusMultistreamDecoder : SafeHandleZeroOrMinusOneIsInvalid, IOpusMultiStreamDecoder, IDisposable { private int _sampleRate; private int _numChannels; private NativeOpusMultistreamDecoder NativeHandle => this; public int SampleRate => _sampleRate; public int NumChannels => _numChannels; public OpusBandwidth Bandwidth { get { NativeOpus.opus_multistream_decoder_ctl(NativeHandle, 4009, out var value); return (OpusBandwidth)value; } } public uint FinalRange { get { NativeOpus.opus_multistream_decoder_ctl(NativeHandle, 4031, out var value); return (uint)value; } } public int Gain { get { NativeOpus.opus_multistream_decoder_ctl(NativeHandle, 4045, out var value); return value; } set { NativeOpus.opus_multistream_decoder_ctl(NativeHandle, 4034, value); } } public int LastPacketDuration { get { NativeOpus.opus_multistream_decoder_ctl(NativeHandle, 4039, out var value); return value; } } internal NativeOpusMultistreamDecoder() : base(ownsHandle: true) { } protected override bool ReleaseHandle() { NativeOpus.opus_multistream_decoder_destroy(handle); return true; } public unsafe static NativeOpusMultistreamDecoder Create(int sampleRate, int channelCount, int streams, int coupledStreams, byte[] channelMapping) { fixed (byte* mapping = channelMapping) { int error; NativeOpusMultistreamDecoder nativeOpusMultistreamDecoder = NativeOpus.opus_multistream_decoder_create(sampleRate, channelCount, streams, coupledStreams, mapping, out error); if (error != 0) { nativeOpusMultistreamDecoder.Dispose(); throw new Exception($"Failed to create opus MS decoder: error {error}"); } nativeOpusMultistreamDecoder._sampleRate = sampleRate; nativeOpusMultistreamDecoder._numChannels = channelCount; return nativeOpusMultistreamDecoder; } } public unsafe int DecodeMultistream(ReadOnlySpan data, Span out_pcm, int frame_size, bool decode_fec) { fixed (float* pcm = out_pcm) { if (data.Length == 0) { return NativeOpus.opus_multistream_decode_float(NativeHandle, null, 0, pcm, frame_size, decode_fec ? 1 : 0); } fixed (byte* data2 = data) { return NativeOpus.opus_multistream_decode_float(NativeHandle, data2, data.Length, pcm, frame_size, decode_fec ? 1 : 0); } } } public unsafe int DecodeMultistream(ReadOnlySpan data, Span out_pcm, int frame_size, bool decode_fec) { fixed (short* pcm = out_pcm) { if (data.Length == 0) { return NativeOpus.opus_multistream_decode(NativeHandle, null, 0, pcm, frame_size, decode_fec ? 1 : 0); } fixed (byte* data2 = data) { return NativeOpus.opus_multistream_decode(NativeHandle, data2, data.Length, pcm, frame_size, decode_fec ? 1 : 0); } } } public void ResetState() { NativeOpus.opus_multistream_decoder_ctl(NativeHandle, 4028, 0); } public string GetVersionString() { return Marshal.PtrToStringAnsi(NativeOpus.opus_get_version_string()); } } internal class NativeOpusMultistreamEncoder : SafeHandleZeroOrMinusOneIsInvalid, IOpusMultiStreamEncoder, IDisposable { private int _sampleRate; private int _numChannels; private NativeOpusMultistreamEncoder NativeHandle => this; public int SampleRate => _sampleRate; public int NumChannels => _numChannels; public int Complexity { get { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4011, out var value); return value; } set { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4010, value); } } public bool UseDTX { get { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4017, out var value); return value != 0; } set { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4016, value ? 1 : 0); } } public int Bitrate { get { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4003, out var value); return value; } set { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4002, value); } } public OpusMode ForceMode { set { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 11002, (int)value); } } public bool UseVBR { get { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4007, out var value); return value != 0; } set { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4006, value ? 1 : 0); } } public OpusApplication Application { get { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4001, out var value); return (OpusApplication)value; } set { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4000, (int)value); } } public OpusBandwidth Bandwidth { get { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4009, out var value); return (OpusBandwidth)value; } set { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4008, (int)value); } } public OpusFramesize ExpertFrameDuration { get { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4041, out var value); return (OpusFramesize)value; } set { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4040, (int)value); } } public uint FinalRange { get { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4031, out var value); return (uint)value; } } public int Lookahead { get { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4027, out var value); return value; } } public int LSBDepth { get { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4037, out var value); return value; } set { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4036, value); } } public OpusBandwidth MaxBandwidth { get { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4005, out var value); return (OpusBandwidth)value; } set { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4004, (int)value); } } public int PacketLossPercent { get { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4015, out var value); return value; } set { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4014, value); } } public bool PredictionDisabled { get { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4043, out var value); return value != 0; } set { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4042, value ? 1 : 0); } } public OpusSignal SignalType { get { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4025, out var value); return (OpusSignal)value; } set { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4024, (int)value); } } public bool UseConstrainedVBR { get { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4021, out var value); return value != 0; } set { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4020, value ? 1 : 0); } } public bool UseInbandFEC { get { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4013, out var value); return value != 0; } set { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4012, value ? 1 : 0); } } internal NativeOpusMultistreamEncoder() : base(ownsHandle: true) { } protected override bool ReleaseHandle() { NativeOpus.opus_multistream_encoder_destroy(handle); return true; } public unsafe static NativeOpusMultistreamEncoder Create(int sampleRate, int channelCount, int mapping_family, out int streams, out int coupled_streams, byte[] mapping, OpusApplication application) { fixed (byte* mapping2 = mapping) { int error; NativeOpusMultistreamEncoder nativeOpusMultistreamEncoder = NativeOpus.opus_multistream_surround_encoder_create(sampleRate, channelCount, mapping_family, out streams, out coupled_streams, mapping2, (int)application, out error); if (error != 0) { nativeOpusMultistreamEncoder.Dispose(); throw new Exception($"Failed to create opus MS encoder: error {error}"); } nativeOpusMultistreamEncoder._sampleRate = sampleRate; nativeOpusMultistreamEncoder._numChannels = channelCount; return nativeOpusMultistreamEncoder; } } public unsafe int EncodeMultistream(ReadOnlySpan in_pcm, int frame_size, Span out_data, int max_data_bytes) { fixed (float* pcm = in_pcm) { fixed (byte* data = out_data) { return NativeOpus.opus_multistream_encode_float(NativeHandle, pcm, frame_size, data, max_data_bytes); } } } public unsafe int EncodeMultistream(ReadOnlySpan in_pcm, int frame_size, Span out_data, int max_data_bytes) { fixed (short* pcm = in_pcm) { fixed (byte* data = out_data) { return NativeOpus.opus_multistream_encode(NativeHandle, pcm, frame_size, data, max_data_bytes); } } } public void ResetState() { NativeOpus.opus_multistream_encoder_ctl(NativeHandle, 4028, 0); } public string GetVersionString() { return Marshal.PtrToStringAnsi(NativeOpus.opus_get_version_string()); } } internal static class NativePlatformUtils { private static bool _cachedPlatformInfoExists = false; private static OSAndArchitecture _cachedPlatformInfo = new OSAndArchitecture(PlatformOperatingSystem.Unknown, PlatformArchitecture.Unknown); private static readonly IDictionary _loadedLibraries = new Dictionary(); private static readonly object _mutex = new object(); private static readonly IReadOnlyDictionary RidInheritanceMappings = new Dictionary { { "android", new string[4] { "linux-bionic", "linux", "unix", "any" } }, { "android-arm", new string[8] { "android", "linux-bionic-arm", "linux-bionic", "linux-arm", "linux", "unix-arm", "unix", "any" } }, { "android-arm64", new string[8] { "android", "linux-bionic-arm64", "linux-bionic", "linux-arm64", "linux", "unix-arm64", "unix", "any" } }, { "android-x64", new string[8] { "android", "linux-bionic-x64", "linux-bionic", "linux-x64", "linux", "unix-x64", "unix", "any" } }, { "android-x86", new string[8] { "android", "linux-bionic-x86", "linux-bionic", "linux-x86", "linux", "unix-x86", "unix", "any" } }, { "any", new string[0] }, { "base", new string[0] }, { "browser", new string[1] { "any" } }, { "browser-wasm", new string[2] { "browser", "any" } }, { "freebsd", new string[2] { "unix", "any" } }, { "freebsd-arm64", new string[4] { "freebsd", "unix-arm64", "unix", "any" } }, { "freebsd-x64", new string[4] { "freebsd", "unix-x64", "unix", "any" } }, { "illumos", new string[2] { "unix", "any" } }, { "illumos-x64", new string[4] { "illumos", "unix-x64", "unix", "any" } }, { "ios", new string[2] { "unix", "any" } }, { "ios-arm", new string[4] { "ios", "unix-arm", "unix", "any" } }, { "ios-arm64", new string[4] { "ios", "unix-arm64", "unix", "any" } }, { "iossimulator", new string[3] { "ios", "unix", "any" } }, { "iossimulator-arm64", new string[6] { "iossimulator", "ios-arm64", "ios", "unix-arm64", "unix", "any" } }, { "iossimulator-x64", new string[6] { "iossimulator", "ios-x64", "ios", "unix-x64", "unix", "any" } }, { "iossimulator-x86", new string[6] { "iossimulator", "ios-x86", "ios", "unix-x86", "unix", "any" } }, { "ios-x64", new string[4] { "ios", "unix-x64", "unix", "any" } }, { "ios-x86", new string[4] { "ios", "unix-x86", "unix", "any" } }, { "linux", new string[2] { "unix", "any" } }, { "linux-arm", new string[4] { "linux", "unix-arm", "unix", "any" } }, { "linux-arm64", new string[4] { "linux", "unix-arm64", "unix", "any" } }, { "linux-armel", new string[4] { "linux", "unix-armel", "unix", "any" } }, { "linux-armv6", new string[4] { "linux", "unix-armv6", "unix", "any" } }, { "linux-bionic", new string[3] { "linux", "unix", "any" } }, { "linux-bionic-arm", new string[6] { "linux-bionic", "linux-arm", "linux", "unix-arm", "unix", "any" } }, { "linux-bionic-arm64", new string[6] { "linux-bionic", "linux-arm64", "linux", "unix-arm64", "unix", "any" } }, { "linux-bionic-x64", new string[6] { "linux-bionic", "linux-x64", "linux", "unix-x64", "unix", "any" } }, { "linux-bionic-x86", new string[6] { "linux-bionic", "linux-x86", "linux", "unix-x86", "unix", "any" } }, { "linux-loongarch64", new string[4] { "linux", "unix-loongarch64", "unix", "any" } }, { "linux-mips64", new string[4] { "linux", "unix-mips64", "unix", "any" } }, { "linux-musl", new string[3] { "linux", "unix", "any" } }, { "linux-musl-arm", new string[6] { "linux-musl", "linux-arm", "linux", "unix-arm", "unix", "any" } }, { "linux-musl-arm64", new string[6] { "linux-musl", "linux-arm64", "linux", "unix-arm64", "unix", "any" } }, { "linux-musl-armel", new string[6] { "linux-musl", "linux-armel", "linux", "unix-armel", "unix", "any" } }, { "linux-musl-armv6", new string[6] { "linux-musl", "linux-armv6", "linux", "unix-armv6", "unix", "any" } }, { "linux-musl-ppc64le", new string[6] { "linux-musl", "linux-ppc64le", "linux", "unix-ppc64le", "unix", "any" } }, { "linux-musl-riscv64", new string[6] { "linux-musl", "linux-riscv64", "linux", "unix-riscv64", "unix", "any" } }, { "linux-musl-s390x", new string[6] { "linux-musl", "linux-s390x", "linux", "unix-s390x", "unix", "any" } }, { "linux-musl-x64", new string[6] { "linux-musl", "linux-x64", "linux", "unix-x64", "unix", "any" } }, { "linux-musl-x86", new string[6] { "linux-musl", "linux-x86", "linux", "unix-x86", "unix", "any" } }, { "linux-ppc64le", new string[4] { "linux", "unix-ppc64le", "unix", "any" } }, { "linux-riscv64", new string[4] { "linux", "unix-riscv64", "unix", "any" } }, { "linux-s390x", new string[4] { "linux", "unix-s390x", "unix", "any" } }, { "linux-x64", new string[4] { "linux", "unix-x64", "unix", "any" } }, { "linux-x86", new string[4] { "linux", "unix-x86", "unix", "any" } }, { "maccatalyst", new string[3] { "ios", "unix", "any" } }, { "maccatalyst-arm64", new string[6] { "maccatalyst", "ios-arm64", "ios", "unix-arm64", "unix", "any" } }, { "maccatalyst-x64", new string[6] { "maccatalyst", "ios-x64", "ios", "unix-x64", "unix", "any" } }, { "osx", new string[2] { "unix", "any" } }, { "osx-arm64", new string[4] { "osx", "unix-arm64", "unix", "any" } }, { "osx-x64", new string[4] { "osx", "unix-x64", "unix", "any" } }, { "solaris", new string[2] { "unix", "any" } }, { "solaris-x64", new string[4] { "solaris", "unix-x64", "unix", "any" } }, { "tvos", new string[2] { "unix", "any" } }, { "tvos-arm64", new string[4] { "tvos", "unix-arm64", "unix", "any" } }, { "tvossimulator", new string[3] { "tvos", "unix", "any" } }, { "tvossimulator-arm64", new string[6] { "tvossimulator", "tvos-arm64", "tvos", "unix-arm64", "unix", "any" } }, { "tvossimulator-x64", new string[6] { "tvossimulator", "tvos-x64", "tvos", "unix-x64", "unix", "any" } }, { "tvos-x64", new string[4] { "tvos", "unix-x64", "unix", "any" } }, { "unix", new string[1] { "any" } }, { "unix-arm", new string[2] { "unix", "any" } }, { "unix-arm64", new string[2] { "unix", "any" } }, { "unix-armel", new string[2] { "unix", "any" } }, { "unix-armv6", new string[2] { "unix", "any" } }, { "unix-loongarch64", new string[2] { "unix", "any" } }, { "unix-mips64", new string[2] { "unix", "any" } }, { "unix-ppc64le", new string[2] { "unix", "any" } }, { "unix-riscv64", new string[2] { "unix", "any" } }, { "unix-s390x", new string[2] { "unix", "any" } }, { "unix-x64", new string[2] { "unix", "any" } }, { "unix-x86", new string[2] { "unix", "any" } }, { "wasi", new string[1] { "any" } }, { "wasi-wasm", new string[2] { "wasi", "any" } }, { "win", new string[1] { "any" } }, { "win-arm", new string[2] { "win", "any" } }, { "win-arm64", new string[2] { "win", "any" } }, { "win-x64", new string[2] { "win", "any" } }, { "win-x86", new string[2] { "win", "any" } } }; internal static OSAndArchitecture GetCurrentPlatform(TextWriter logger) { lock (_mutex) { if (!_cachedPlatformInfoExists) { _cachedPlatformInfo = GetCurrentPlatformInternal(logger); } return _cachedPlatformInfo; } } internal static OSAndArchitecture GetCurrentPlatformInternal(TextWriter logger) { PlatformOperatingSystem platformOperatingSystem = PlatformOperatingSystem.Unknown; PlatformArchitecture platformArchitecture = PlatformArchitecture.Unknown; if (platformOperatingSystem == PlatformOperatingSystem.Unknown) { try { switch (Environment.OSVersion.Platform) { case PlatformID.Win32S: case PlatformID.Win32Windows: case PlatformID.Win32NT: case PlatformID.WinCE: platformOperatingSystem = PlatformOperatingSystem.Windows; break; case PlatformID.Unix: case PlatformID.MacOSX: platformOperatingSystem = ((File.Exists("/proc/sys/kernel/ostype") && File.ReadAllText("/proc/sys/kernel/ostype").StartsWith("Linux", StringComparison.OrdinalIgnoreCase)) ? PlatformOperatingSystem.Linux : ((!File.Exists("/System/Library/CoreServices/SystemVersion.plist")) ? PlatformOperatingSystem.Unix : PlatformOperatingSystem.MacOS)); break; case PlatformID.Xbox: break; } } catch (Exception ex) { logger?.WriteLine(ex.ToString()); } } if (platformOperatingSystem != 0 && platformArchitecture == PlatformArchitecture.Unknown) { platformArchitecture = TryGetNativeArchitecture(platformOperatingSystem, logger); } if (platformArchitecture == PlatformArchitecture.Unknown) { platformArchitecture = (Environment.Is64BitProcess ? PlatformArchitecture.X64 : PlatformArchitecture.I386); } return new OSAndArchitecture(platformOperatingSystem, platformArchitecture); } internal static NativeLibraryStatus PrepareNativeLibrary(string libraryName, TextWriter logger) { logger?.WriteLine("Preparing native library \"{0}\"", libraryName); OSAndArchitecture currentPlatform = GetCurrentPlatform(logger); logger?.WriteLine("Detected current platform as \"{0}\"", currentPlatform); string text = NormalizeLibraryName(libraryName, currentPlatform); lock (_mutex) { if (_loadedLibraries.TryGetValue(text, out var value)) { logger?.WriteLine("Native library \"{0}\" has already been prepared; nothing to do", libraryName); return value; } if (currentPlatform.OS == PlatformOperatingSystem.Android) { logger?.WriteLine("Probing for " + text + " within local Android .apk"); if (ProbeLibrary(text, currentPlatform, logger) != NativeLibraryStatus.Available) { logger?.WriteLine("Native library \"{0}\" was not found in the local .apk.", libraryName); return NativeLibraryStatus.Unavailable; } return NativeLibraryStatus.Available; } logger?.WriteLine("Probing for an already existing " + text); NativeLibraryStatus nativeLibraryStatus = ProbeLibrary(text, currentPlatform, logger); if (nativeLibraryStatus == NativeLibraryStatus.Available) { logger?.WriteLine("Native library \"{0}\" resolved to an already-existing library. Loading current file as-is.", libraryName); _loadedLibraries[text] = nativeLibraryStatus; return nativeLibraryStatus; } DeleteLocalLibraryIfPresent(text, logger); string path = Path.Combine(Environment.CurrentDirectory, "runtimes"); List list = PermuteLibraryNames(libraryName, currentPlatform); foreach (string item in PermuteArchitectureSpecificDirectoryNames(currentPlatform)) { DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(path, item, "native")); if (!directoryInfo.Exists) { continue; } foreach (string item2 in list) { FileInfo fileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, item2)); if (!fileInfo.Exists) { continue; } if (currentPlatform.OS == PlatformOperatingSystem.Windows || currentPlatform.OS == PlatformOperatingSystem.Linux || currentPlatform.OS == PlatformOperatingSystem.MacOS) { FileInfo fileInfo2 = new FileInfo(Path.Combine(Environment.CurrentDirectory, text)); try { logger?.WriteLine("Resolved native library \"" + libraryName + "\" to " + fileInfo.FullName); fileInfo.CopyTo(fileInfo2.FullName); _loadedLibraries[text] = NativeLibraryStatus.Available; return NativeLibraryStatus.Available; } catch (Exception ex) { logger?.WriteLine(ex.Message); logger?.WriteLine("Could not prepare native library \"" + libraryName + "\" (is the existing library file locked or in use?)"); _loadedLibraries[text] = NativeLibraryStatus.Unknown; return NativeLibraryStatus.Unknown; } } throw new PlatformNotSupportedException($"Don't know yet how to load libraries for {currentPlatform.OS}"); } } logger?.WriteLine("Failed to resolve native library \"{0}\".", libraryName); _loadedLibraries[text] = NativeLibraryStatus.Unavailable; return NativeLibraryStatus.Unavailable; } } internal static string GetRuntimeIdString(this PlatformArchitecture architecture) { return architecture switch { PlatformArchitecture.Unknown => "unknown", PlatformArchitecture.Any => "any", PlatformArchitecture.I386 => "x86", PlatformArchitecture.X64 => "x64", PlatformArchitecture.ArmV7 => "arm", PlatformArchitecture.Arm64 => "arm64", PlatformArchitecture.Armel => "armel", PlatformArchitecture.ArmV6 => "armv6", PlatformArchitecture.Mips64 => "mips64", PlatformArchitecture.PowerPC64 => "ppc64le", PlatformArchitecture.RiscFive => "riscv64", PlatformArchitecture.S390x => "s390x", PlatformArchitecture.Loongarch64 => "loongarch64", PlatformArchitecture.Itanium64 => "ia64", _ => throw new PlatformNotSupportedException("No runtime ID defined for " + architecture), }; } internal static string GetRuntimeIdString(this PlatformOperatingSystem os) { return os switch { PlatformOperatingSystem.Unknown => "unknown", PlatformOperatingSystem.Any => "any", PlatformOperatingSystem.Windows => "win", PlatformOperatingSystem.Linux => "linux", PlatformOperatingSystem.MacOS => "osx", PlatformOperatingSystem.iOS => "ios", PlatformOperatingSystem.iOS_Simulator => "iossimulator", PlatformOperatingSystem.Android => "android", PlatformOperatingSystem.FreeBSD => "freebsd", PlatformOperatingSystem.Illumos => "illumos", PlatformOperatingSystem.Linux_Bionic => "linux-bionic", PlatformOperatingSystem.Linux_Musl => "linux-musl", PlatformOperatingSystem.MacCatalyst => "maccatalyst", PlatformOperatingSystem.Solaris => "solaris", PlatformOperatingSystem.TvOS => "tvos", PlatformOperatingSystem.TvOS_Simulator => "tvossimulator", PlatformOperatingSystem.Unix => "unix", PlatformOperatingSystem.Browser => "browser", PlatformOperatingSystem.Wasi => "wasi", _ => throw new PlatformNotSupportedException("No runtime ID defined for " + os), }; } internal static string[] GetInheritedRuntimeIds(string runtimeId) { if (RidInheritanceMappings.TryGetValue(runtimeId, out var value)) { return value; } return new string[0]; } internal static OSAndArchitecture ParseRuntimeId(ReadOnlySpan runtimeId) { int num = runtimeId.IndexOf('-'); if (num < 0) { return new OSAndArchitecture(TryParseOperatingSystemString(runtimeId), PlatformArchitecture.Unknown); } return new OSAndArchitecture(TryParseOperatingSystemString(runtimeId.Slice(0, num)), TryParseArchitectureString(runtimeId.Slice(num + 1))); } internal static PlatformOperatingSystem TryParseOperatingSystemString(string os) { return TryParseOperatingSystemString(os.AsSpan()); } internal static PlatformOperatingSystem TryParseOperatingSystemString(ReadOnlySpan os) { if (os.Length >= "win".Length && MemoryExtensions.Equals(os.Slice(0, "win".Length), "win".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.Windows; } if (os.Length >= "linux".Length && MemoryExtensions.Equals(os.Slice(0, "linux".Length), "linux".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.Linux; } if (os.Length >= "ubuntu".Length && MemoryExtensions.Equals(os.Slice(0, "ubuntu".Length), "ubuntu".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.Linux; } if (os.Length >= "debian".Length && MemoryExtensions.Equals(os.Slice(0, "debian".Length), "debian".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.Linux; } if (os.Length >= "osx".Length && MemoryExtensions.Equals(os.Slice(0, "osx".Length), "osx".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.MacOS; } if (os.Length >= "ios".Length && MemoryExtensions.Equals(os.Slice(0, "ios".Length), "ios".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.iOS; } if (os.Length >= "iossimulator".Length && MemoryExtensions.Equals(os.Slice(0, "iossimulator".Length), "iossimulator".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.iOS_Simulator; } if (os.Length >= "android".Length && MemoryExtensions.Equals(os.Slice(0, "android".Length), "android".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.Android; } if (os.Length >= "freebsd".Length && MemoryExtensions.Equals(os.Slice(0, "freebsd".Length), "freebsd".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.FreeBSD; } if (os.Length >= "illumos".Length && MemoryExtensions.Equals(os.Slice(0, "illumos".Length), "illumos".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.Illumos; } if (os.Length >= "linux-bionic".Length && MemoryExtensions.Equals(os.Slice(0, "linux-bionic".Length), "linux-bionic".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.Linux_Bionic; } if (os.Length >= "linux-musl".Length && MemoryExtensions.Equals(os.Slice(0, "linux-musl".Length), "linux-musl".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.Linux_Musl; } if (os.Length >= "maccatalyst".Length && MemoryExtensions.Equals(os.Slice(0, "maccatalyst".Length), "maccatalyst".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.MacCatalyst; } if (os.Length >= "solaris".Length && MemoryExtensions.Equals(os.Slice(0, "solaris".Length), "solaris".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.Solaris; } if (os.Length >= "tvos".Length && MemoryExtensions.Equals(os.Slice(0, "tvos".Length), "tvos".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.TvOS; } if (os.Length >= "tvossimulator".Length && MemoryExtensions.Equals(os.Slice(0, "tvossimulator".Length), "tvossimulator".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.TvOS_Simulator; } if (os.Length >= "unix".Length && MemoryExtensions.Equals(os.Slice(0, "unix".Length), "unix".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.Unix; } if (os.Length >= "browser".Length && MemoryExtensions.Equals(os.Slice(0, "browser".Length), "browser".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.Browser; } if (os.Length >= "wasi".Length && MemoryExtensions.Equals(os.Slice(0, "wasi".Length), "wasi".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformOperatingSystem.Wasi; } return PlatformOperatingSystem.Unknown; } internal static PlatformArchitecture TryParseArchitectureString(string arch) { return TryParseArchitectureString(arch.AsSpan()); } internal static PlatformArchitecture TryParseArchitectureString(ReadOnlySpan arch) { if (MemoryExtensions.Equals(arch, "any".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformArchitecture.Any; } if (MemoryExtensions.Equals(arch, "x86".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformArchitecture.I386; } if (MemoryExtensions.Equals(arch, "x64".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformArchitecture.X64; } if (MemoryExtensions.Equals(arch, "arm".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformArchitecture.ArmV7; } if (MemoryExtensions.Equals(arch, "arm64".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformArchitecture.Arm64; } if (MemoryExtensions.Equals(arch, "armel".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformArchitecture.Armel; } if (MemoryExtensions.Equals(arch, "armv6".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformArchitecture.ArmV6; } if (MemoryExtensions.Equals(arch, "mips64".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformArchitecture.Mips64; } if (MemoryExtensions.Equals(arch, "ppc64le".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformArchitecture.PowerPC64; } if (MemoryExtensions.Equals(arch, "riscv64".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformArchitecture.RiscFive; } if (MemoryExtensions.Equals(arch, "s390x".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformArchitecture.S390x; } if (MemoryExtensions.Equals(arch, "loongarch64".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformArchitecture.Loongarch64; } if (MemoryExtensions.Equals(arch, "ia64".AsSpan(), StringComparison.OrdinalIgnoreCase)) { return PlatformArchitecture.Itanium64; } return PlatformArchitecture.Unknown; } internal static PlatformArchitecture TryGetNativeArchitecture(PlatformOperatingSystem os, TextWriter logger) { switch (os) { case PlatformOperatingSystem.Windows: { KernelInteropWindows.SYSTEM_INFO Info = default(KernelInteropWindows.SYSTEM_INFO); KernelInteropWindows.GetSystemInfo(ref Info); switch (Info.wProcessorArchitecture) { case 0: case 9: if (Marshal.SizeOf((IntPtr)0) != 4) { return PlatformArchitecture.X64; } return PlatformArchitecture.I386; case 5: return PlatformArchitecture.ArmV7; case 18: return PlatformArchitecture.Arm64; case 6: return PlatformArchitecture.Itanium64; default: return PlatformArchitecture.Unknown; } } case PlatformOperatingSystem.Linux: case PlatformOperatingSystem.Android: case PlatformOperatingSystem.Linux_Bionic: case PlatformOperatingSystem.Linux_Musl: case PlatformOperatingSystem.Unix: { PlatformArchitecture? platformArchitecture = KernelInteropLinux.TryGetArchForUnix(logger); if (platformArchitecture.HasValue) { return platformArchitecture.Value; } break; } } return PlatformArchitecture.Unknown; } private static void DeleteLocalLibraryIfPresent(string normalizedLibraryName, TextWriter logger) { FileInfo fileInfo = new FileInfo(Path.Combine(Environment.CurrentDirectory, normalizedLibraryName)); if (fileInfo.Exists) { try { logger?.WriteLine("Clobbering existing file " + fileInfo.FullName); fileInfo.Delete(); } catch (Exception) { logger?.WriteLine("Failed to clean up \"" + fileInfo.FullName + "\" (is it locked or in use?)"); } } } private static List PermuteArchitectureSpecificDirectoryNames(OSAndArchitecture platformInfo) { string text = platformInfo.OS.GetRuntimeIdString() + "-" + platformInfo.Architecture.GetRuntimeIdString(); string[] inheritedRuntimeIds = GetInheritedRuntimeIds(text); List list = new List(inheritedRuntimeIds.Length + 1); list.Add(text); if (platformInfo.OS == PlatformOperatingSystem.Windows) { list.Add("win10-" + platformInfo.Architecture.GetRuntimeIdString()); list.Add("win81-" + platformInfo.Architecture.GetRuntimeIdString()); list.Add("win8-" + platformInfo.Architecture.GetRuntimeIdString()); list.Add("win7-" + platformInfo.Architecture.GetRuntimeIdString()); list.Add("win10"); list.Add("win81"); list.Add("win8"); list.Add("win7"); } list.AddRange(inheritedRuntimeIds); return list; } private static string LibraryNameWithoutExtension(string libraryName) { if (!libraryName.Contains(".")) { return libraryName; } string text = libraryName.ToLowerInvariant(); if (text.EndsWith(".dll") || text.EndsWith(".so") || text.EndsWith(".dylib")) { return libraryName.Substring(0, libraryName.LastIndexOf('.')); } return libraryName; } private static string NormalizeLibraryName(string requestedName, OSAndArchitecture platformInfo) { string text = LibraryNameWithoutExtension(requestedName); if (platformInfo.OS == PlatformOperatingSystem.Windows) { return text + ".dll"; } if (platformInfo.OS == PlatformOperatingSystem.Linux || platformInfo.OS == PlatformOperatingSystem.Android || platformInfo.OS == PlatformOperatingSystem.Linux_Bionic || platformInfo.OS == PlatformOperatingSystem.Linux_Musl || platformInfo.OS == PlatformOperatingSystem.Unix) { if (!text.StartsWith("lib", StringComparison.Ordinal)) { return "lib" + text + ".so"; } return text + ".so"; } if (platformInfo.OS == PlatformOperatingSystem.iOS || platformInfo.OS == PlatformOperatingSystem.iOS_Simulator || platformInfo.OS == PlatformOperatingSystem.MacOS || platformInfo.OS == PlatformOperatingSystem.MacCatalyst) { if (!text.StartsWith("lib", StringComparison.Ordinal)) { return "lib" + text + ".dylib"; } return text + ".dylib"; } return requestedName; } private static List PermuteLibraryNames(string requestedName, OSAndArchitecture platformInfo) { List list = new List(16); string text = LibraryNameWithoutExtension(requestedName); if (platformInfo.OS == PlatformOperatingSystem.Windows) { list.Add(text + ".dll"); list.Add("lib" + text + ".dll"); if (platformInfo.Architecture == PlatformArchitecture.I386) { list.Add(text + "_x86.dll"); list.Add("lib" + text + "_x86.dll"); list.Add(text + "x86.dll"); list.Add("lib" + text + "x86.dll"); list.Add(text + "32.dll"); list.Add("lib" + text + "32.dll"); list.Add(text + "_32.dll"); list.Add("lib" + text + "_32.dll"); list.Add(text + "-32.dll"); list.Add("lib" + text + "-32.dll"); } if (platformInfo.Architecture == PlatformArchitecture.X64) { list.Add(text + "_x64.dll"); list.Add("lib" + text + "_x64.dll"); list.Add(text + "x64.dll"); list.Add("lib" + text + "x64.dll"); list.Add(text + "64.dll"); list.Add("lib" + text + "64.dll"); list.Add(text + "_64.dll"); list.Add("lib" + text + "_64.dll"); list.Add(text + "-64.dll"); list.Add("lib" + text + "-64.dll"); } } else if (platformInfo.OS == PlatformOperatingSystem.Linux || platformInfo.OS == PlatformOperatingSystem.Android || platformInfo.OS == PlatformOperatingSystem.Linux_Bionic || platformInfo.OS == PlatformOperatingSystem.Linux_Musl || platformInfo.OS == PlatformOperatingSystem.Unix) { list.Add(text + ".so"); list.Add("lib" + text + ".so"); } else if (platformInfo.OS == PlatformOperatingSystem.MacOS || platformInfo.OS == PlatformOperatingSystem.MacCatalyst || platformInfo.OS == PlatformOperatingSystem.iOS || platformInfo.OS == PlatformOperatingSystem.iOS_Simulator) { list.Add(text + ".dylib"); list.Add("lib" + text + ".dylib"); } else { list.Add(requestedName); } return list; } internal static NativeLibraryStatus ProbeLibrary(string libName, OSAndArchitecture platformInfo, TextWriter logger) { try { if (platformInfo.OS == PlatformOperatingSystem.Windows) { IntPtr intPtr = IntPtr.Zero; try { logger?.WriteLine("Attempting to load " + libName + " as a windows .dll"); KernelInteropWindows.GetLastError(); intPtr = KernelInteropWindows.LoadLibraryExW(libName, IntPtr.Zero, 4096u); if (intPtr == IntPtr.Zero) { uint lastError = KernelInteropWindows.GetLastError(); if (lastError != 0) { uint num = 0x80070000u | lastError; switch (num) { case 2147942526u: logger?.WriteLine($"Win32 error 0x{num:X8}: File {libName} not found"); break; case 2147942593u: logger?.WriteLine($"Win32 error 0x{num:X8}: Invalid binary format while loading library {libName}"); break; default: logger?.WriteLine($"Win32 error 0x{num:X8} while loading library {libName}"); break; } } else { logger?.WriteLine("Native library " + libName + " not found."); } return NativeLibraryStatus.Unavailable; } logger?.WriteLine("Native library " + libName + " found!"); return NativeLibraryStatus.Available; } finally { if (intPtr != IntPtr.Zero) { KernelInteropWindows.FreeLibrary(intPtr); } } } if (platformInfo.OS == PlatformOperatingSystem.Linux || platformInfo.OS == PlatformOperatingSystem.Android || platformInfo.OS == PlatformOperatingSystem.Linux_Bionic || platformInfo.OS == PlatformOperatingSystem.Linux_Musl || platformInfo.OS == PlatformOperatingSystem.Unix) { IntPtr intPtr2 = IntPtr.Zero; try { logger?.WriteLine("Attempting to load " + libName + " as a linux .so"); intPtr2 = KernelInteropLinux.dlopen(libName, 2); if (intPtr2 == IntPtr.Zero) { IntPtr intPtr3 = KernelInteropLinux.dlerror(); if (intPtr3 != IntPtr.Zero) { string text = Marshal.PtrToStringAnsi(intPtr3); if (!string.IsNullOrEmpty(text)) { logger?.WriteLine($"Error while loading library {libName}: {text}"); } else { logger?.WriteLine(libName + " could not be loaded."); } } else { logger?.WriteLine(libName + " could not be loaded."); } return NativeLibraryStatus.Unavailable; } logger?.WriteLine("Native library " + libName + " found!"); return NativeLibraryStatus.Available; } finally { if (intPtr2 != IntPtr.Zero) { KernelInteropLinux.dlclose(intPtr2); } } } if (platformInfo.OS == PlatformOperatingSystem.MacOS || platformInfo.OS == PlatformOperatingSystem.MacCatalyst || platformInfo.OS == PlatformOperatingSystem.iOS || platformInfo.OS == PlatformOperatingSystem.iOS_Simulator) { IntPtr intPtr4 = IntPtr.Zero; try { logger?.WriteLine("Attempting to load " + libName + " as a macOS .dylib"); intPtr4 = KernelInteropMacOS.dlopen(libName, 2); if (intPtr4 == IntPtr.Zero) { IntPtr intPtr5 = KernelInteropMacOS.dlerror(); if (intPtr5 != IntPtr.Zero) { string text2 = Marshal.PtrToStringAnsi(intPtr5); if (!string.IsNullOrEmpty(text2)) { logger?.WriteLine($"Error while loading library {libName}: {text2}"); } else { logger?.WriteLine(libName + " could not be loaded."); } } else { logger?.WriteLine(libName + " could not be loaded."); } return NativeLibraryStatus.Unavailable; } logger?.WriteLine("Native library " + libName + " found!"); return NativeLibraryStatus.Available; } finally { if (intPtr4 != IntPtr.Zero) { KernelInteropMacOS.dlclose(intPtr4); } } } } catch (Exception value) { logger?.WriteLine(value); } return NativeLibraryStatus.Unknown; } } internal readonly struct OSAndArchitecture : IEquatable { public PlatformOperatingSystem OS { get; } public PlatformArchitecture Architecture { get; } public OSAndArchitecture(PlatformOperatingSystem OS, PlatformArchitecture architecture) { this.OS = OS; Architecture = architecture; } public override string ToString() { return OS.GetRuntimeIdString() + "-" + Architecture.GetRuntimeIdString(); } public override int GetHashCode() { return OS.GetHashCode() * 17 + Architecture.GetHashCode() * 37119; } public override bool Equals(object other) { if (other == null || GetType() != other.GetType()) { return false; } return Equals((OSAndArchitecture)other); } public bool Equals(OSAndArchitecture other) { if (OS == other.OS) { return Architecture == other.Architecture; } return false; } public static bool operator ==(OSAndArchitecture left, OSAndArchitecture right) { return left.Equals(right); } public static bool operator !=(OSAndArchitecture left, OSAndArchitecture right) { return !(left == right); } } internal enum PlatformArchitecture { Unknown, Any, I386, X64, ArmV7, Arm64, Armel, ArmV6, Mips64, PowerPC64, RiscFive, S390x, Loongarch64, Itanium64 } internal enum PlatformOperatingSystem { Unknown, Any, Windows, Linux, MacOS, iOS, iOS_Simulator, Android, FreeBSD, Illumos, Linux_Bionic, Linux_Musl, MacCatalyst, Solaris, TvOS, TvOS_Simulator, Unix, Browser, Wasi } } namespace Concentus.Common { internal static class Autocorrelation { private const int QC = 10; private const int QS = 14; internal static void silk_autocorr(int[] results, out int scale, short[] inputData, int inputDataSize, int correlationCount) { int num = Inlines.silk_min_int(inputDataSize, correlationCount); scale = _celt_autocorr(inputData, results, num - 1, inputDataSize); } internal static int _celt_autocorr(short[] x, int[] ac, int lag, int n) { int num = n - lag; short[] array = new short[n]; short[] array2 = x; int num2 = 0; int num3 = 1 + (n << 7); if (((uint)n & (true ? 1u : 0u)) != 0) { num3 += Inlines.SHR32(Inlines.MULT16_16(array2[0], array2[0]), 9); } for (int i = n & 1; i < n; i += 2) { num3 += Inlines.SHR32(Inlines.MULT16_16(array2[i], array2[i]), 9); num3 += Inlines.SHR32(Inlines.MULT16_16(array2[i + 1], array2[i + 1]), 9); } num2 = Inlines.celt_ilog2(num3) - 30 + 10; num2 /= 2; if (num2 > 0) { for (int i = 0; i < n; i++) { array[i] = (short)Inlines.PSHR32(array2[i], num2); } array2 = array; } else { num2 = 0; } CeltPitchXCorr.pitch_xcorr(array2, 0, array2, 0, ac, num, lag + 1); for (int j = 0; j <= lag; j++) { int i = j + num; int num4 = 0; for (; i < n; i++) { num4 = Inlines.MAC16_16(num4, array2[i], array2[i - j]); } ac[j] += num4; } num2 = 2 * num2; if (num2 <= 0) { ac[0] += Inlines.SHL32(1, -num2); } if (ac[0] < 268435456) { int num5 = 29 - Inlines.EC_ILOG((uint)ac[0]); for (int i = 0; i <= lag; i++) { ac[i] = Inlines.SHL32(ac[i], num5); } num2 -= num5; } else if (ac[0] >= 536870912) { int num6 = 1; if (ac[0] >= 1073741824) { num6++; } for (int i = 0; i <= lag; i++) { ac[i] = Inlines.SHR32(ac[i], num6); } num2 += num6; } return num2; } internal static int _celt_autocorr(int[] x, int[] ac, int[] window, int overlap, int lag, int n) { int num = n - lag; int[] array = new int[n]; int[] array2; if (overlap == 0) { array2 = x; } else { for (int i = 0; i < n; i++) { array[i] = x[i]; } for (int i = 0; i < overlap; i++) { array[i] = Inlines.MULT16_16_Q15(x[i], window[i]); array[n - i - 1] = Inlines.MULT16_16_Q15(x[n - i - 1], window[i]); } array2 = array; } int num2 = 0; int num3 = 1 + (n << 7); if (((uint)n & (true ? 1u : 0u)) != 0) { num3 += Inlines.SHR32(Inlines.MULT16_16(array2[0], array2[0]), 9); } for (int i = n & 1; i < n; i += 2) { num3 += Inlines.SHR32(Inlines.MULT16_16(array2[i], array2[i]), 9); num3 += Inlines.SHR32(Inlines.MULT16_16(array2[i + 1], array2[i + 1]), 9); } num2 = Inlines.celt_ilog2(num3) - 30 + 10; num2 /= 2; if (num2 > 0) { for (int i = 0; i < n; i++) { array[i] = Inlines.PSHR32(array2[i], num2); } array2 = array; } else { num2 = 0; } CeltPitchXCorr.pitch_xcorr(array2, 0, array2, 0, ac, num, lag + 1); for (int j = 0; j <= lag; j++) { int i = j + num; int num4 = 0; for (; i < n; i++) { num4 = Inlines.MAC16_16(num4, array2[i], array2[i - j]); } ac[j] += num4; } num2 = 2 * num2; if (num2 <= 0) { ac[0] += Inlines.SHL32(1, -num2); } if (ac[0] < 268435456) { int num5 = 29 - Inlines.EC_ILOG((uint)ac[0]); for (int i = 0; i <= lag; i++) { ac[i] = Inlines.SHL32(ac[i], num5); } num2 -= num5; } else if (ac[0] >= 536870912) { int num6 = 1; if (ac[0] >= 1073741824) { num6++; } for (int i = 0; i <= lag; i++) { ac[i] = Inlines.SHR32(ac[i], num6); } num2 += num6; } return num2; } internal static void silk_warped_autocorrelation(int[] corr, out int scale, short[] input, int warping_Q16, int length, int order) { Span span = new int[order + 1]; Span span2 = new long[order + 1]; for (int i = 0; i < length; i++) { int num = Inlines.silk_LSHIFT32(input[i], 14); for (int j = 0; j < order; j += 2) { int num2 = Inlines.silk_SMLAWB(span[j], span[j + 1] - num, warping_Q16); span[j] = num; span2[j] += Inlines.silk_RSHIFT64(Inlines.silk_SMULL(num, span[0]), 18); num = Inlines.silk_SMLAWB(span[j + 1], span[j + 2] - num2, warping_Q16); span[j + 1] = num2; span2[j + 1] += Inlines.silk_RSHIFT64(Inlines.silk_SMULL(num2, span[0]), 18); } span[order] = num; span2[order] += Inlines.silk_RSHIFT64(Inlines.silk_SMULL(num, span[0]), 18); } int a = Inlines.silk_CLZ64(span2[0]) - 35; a = Inlines.silk_LIMIT(a, -22, 20); scale = -(10 + a); if (a >= 0) { for (int j = 0; j < order + 1; j++) { corr[j] = (int)Inlines.silk_LSHIFT64(span2[j], a); } } else { for (int j = 0; j < order + 1; j++) { corr[j] = (int)Inlines.silk_RSHIFT64(span2[j], -a); } } } } internal class EntropyCoder { private const int EC_WINDOW_SIZE = 32; private const int EC_UINT_BITS = 8; internal const int BITRES = 3; private const int EC_SYM_BITS = 8; private const int EC_CODE_BITS = 32; private const uint EC_SYM_MAX = 255u; private const uint EC_CODE_SHIFT = 23u; private const uint EC_CODE_TOP = 2147483648u; private const uint EC_CODE_BOT = 8388608u; private const int EC_CODE_EXTRA = 7; internal uint storage; internal uint end_offs; internal uint end_window; internal int nend_bits; internal int nbits_total; internal uint offs; internal uint rng; internal uint val; internal uint ext; internal int rem; internal int error; private static readonly uint[] correction = new uint[8] { 35733u, 38967u, 42495u, 46340u, 50535u, 55109u, 60097u, 65535u }; internal EntropyCoder() { Reset(); } internal void Reset() { storage = 0u; end_offs = 0u; end_window = 0u; nend_bits = 0; offs = 0u; rng = 0u; val = 0u; ext = 0u; rem = 0; error = 0; } internal void Assign(EntropyCoder other) { storage = other.storage; end_offs = other.end_offs; end_window = other.end_window; nend_bits = other.nend_bits; nbits_total = other.nbits_total; offs = other.offs; rng = other.rng; val = other.val; ext = other.ext; rem = other.rem; error = other.error; } internal int read_byte(ReadOnlySpan buf) { if (offs >= storage) { return 0; } return buf[(int)offs++]; } internal int read_byte_from_end(ReadOnlySpan buf) { if (end_offs >= storage) { return 0; } return buf[(int)(storage - ++end_offs)]; } internal int write_byte(Span buf, uint _value) { if (offs + end_offs >= storage) { return -1; } buf[(int)offs++] = (byte)_value; return 0; } internal int write_byte_at_end(Span buf, uint _value) { if (offs + end_offs >= storage) { return -1; } buf[(int)(storage - ++end_offs)] = (byte)_value; return 0; } internal void dec_normalize(ReadOnlySpan buf) { while (rng <= 8388608) { nbits_total += 8; rng <<= 8; int num = rem; rem = read_byte(buf); num = ((num << 8) | rem) >> 1; val = (uint)(int)((val << 8) + (0xFFuL & (ulong)(~num))) & 0x7FFFFFFFu; } } internal void dec_init(ReadOnlySpan buf, uint _storage) { storage = _storage; end_offs = 0u; end_window = 0u; nend_bits = 0; nbits_total = 9; offs = 0u; rng = 128u; rem = read_byte(buf); val = rng - 1 - (uint)(rem >> 1); error = 0; dec_normalize(buf); } internal uint decode(uint _ft) { ext = rng / _ft; uint num = val / ext; return _ft - Inlines.EC_MINI(num + 1, _ft); } internal uint decode_bin(uint _bits) { ext = rng >> (int)_bits; uint num = val / ext; return (uint)(1 << (int)_bits) - Inlines.EC_MINI(num + 1, (uint)(1 << (int)_bits)); } internal void dec_update(ReadOnlySpan buf, uint _fl, uint _fh, uint _ft) { uint num = ext * (_ft - _fh); val -= num; rng = ((_fl != 0) ? (ext * (_fh - _fl)) : (rng - num)); dec_normalize(buf); } internal int dec_bit_logp(ReadOnlySpan buf, uint _logp) { uint num = rng; uint num2 = val; uint num3 = num >> (int)_logp; int num4 = ((num2 < num3) ? 1 : 0); if (num4 == 0) { val = num2 - num3; } rng = ((num4 != 0) ? num3 : (num - num3)); dec_normalize(buf); return num4; } internal int dec_icdf(ReadOnlySpan buf, byte[] _icdf, uint _ftb) { uint num = rng; uint num2 = val; uint num3 = num >> (int)_ftb; int num4 = -1; uint num5; do { num5 = num; num = num3 * _icdf[++num4]; } while (num2 < num); val = num2 - num; rng = num5 - num; dec_normalize(buf); return num4; } internal int dec_icdf(ReadOnlySpan buf, byte[] _icdf, int _icdf_offset, uint _ftb) { uint num = rng; uint num2 = val; uint num3 = num >> (int)_ftb; int num4 = _icdf_offset - 1; uint num5; do { num5 = num; num = num3 * _icdf[++num4]; } while (num2 < num); val = num2 - num; rng = num5 - num; dec_normalize(buf); return num4 - _icdf_offset; } internal uint dec_uint(ReadOnlySpan buf, uint _ft) { _ft--; int num = Inlines.EC_ILOG(_ft); uint num2; if (num > 8) { num -= 8; uint ft = (_ft >> num) + 1; num2 = decode(ft); dec_update(buf, num2, num2 + 1, ft); uint num3 = (num2 << num) | dec_bits(buf, (uint)num); if (num3 <= _ft) { return num3; } error = 1; return _ft; } _ft++; num2 = decode(_ft); dec_update(buf, num2, num2 + 1, _ft); return num2; } internal uint dec_bits(ReadOnlySpan buf, uint _bits) { uint num = end_window; int num2 = nend_bits; if ((uint)num2 < _bits) { do { num |= (uint)(read_byte_from_end(buf) << num2); num2 += 8; } while (num2 <= 24); } int result = (int)num & ((1 << (int)_bits) - 1); num >>= (int)_bits; num2 -= (int)_bits; end_window = num; nend_bits = num2; nbits_total += (int)_bits; return (uint)result; } internal void enc_carry_out(Span buf, int _c) { if ((long)_c != 255) { int num = _c >> 8; if (rem >= 0) { error |= write_byte(buf, (uint)(rem + num)); } if (ext != 0) { uint value = (uint)(255 + num) & 0xFFu; do { error |= write_byte(buf, value); } while (--ext != 0); } rem = _c & 0xFF; } else { ext++; } } internal void enc_normalize(Span buf) { while (rng <= 8388608) { enc_carry_out(buf, (int)(val >> 23)); val = (val << 8) & 0x7FFFFFFFu; rng <<= 8; nbits_total += 8; } } internal void enc_init(uint _size) { end_offs = 0u; end_window = 0u; nend_bits = 0; nbits_total = 33; offs = 0u; rng = 2147483648u; rem = -1; val = 0u; ext = 0u; storage = _size; error = 0; } internal void encode(Span buf, uint _fl, uint _fh, uint _ft) { uint num = rng / _ft; if (_fl != 0) { val += rng - num * (_ft - _fl); rng = num * (_fh - _fl); } else { rng -= num * (_ft - _fh); } enc_normalize(buf); } internal void encode_bin(Span buf, uint _fl, uint _fh, uint _bits) { uint num = rng >> (int)_bits; if (_fl != 0) { val += (uint)((int)rng - (int)num * ((1 << (int)_bits) - (int)_fl)); rng = num * (_fh - _fl); } else { rng -= (uint)((int)num * ((1 << (int)_bits) - (int)_fh)); } enc_normalize(buf); } internal void enc_bit_logp(Span buf, int _val, uint _logp) { uint num = rng; uint num2 = val; uint num3 = num >> (int)_logp; num -= num3; if (_val != 0) { val = num2 + num; } rng = ((_val != 0) ? num3 : num); enc_normalize(buf); } internal void enc_icdf(Span buf, int _s, byte[] _icdf, uint _ftb) { uint num = rng >> (int)_ftb; if (_s > 0) { val += rng - num * _icdf[_s - 1]; rng = num * (uint)(_icdf[_s - 1] - _icdf[_s]); } else { rng -= num * _icdf[_s]; } enc_normalize(buf); } internal void enc_icdf(Span buf, int _s, byte[] _icdf, int icdf_ptr, uint _ftb) { uint num = rng >> (int)_ftb; if (_s > 0) { val += rng - num * _icdf[icdf_ptr + _s - 1]; rng = num * (uint)(_icdf[icdf_ptr + _s - 1] - _icdf[icdf_ptr + _s]); } else { rng -= num * _icdf[icdf_ptr + _s]; } enc_normalize(buf); } internal void enc_uint(Span buf, uint _fl, uint _ft) { _ft--; int num = Inlines.EC_ILOG(_ft); if (num > 8) { num -= 8; uint ft = (_ft >> num) + 1; uint num2 = _fl >> num; encode(buf, num2, num2 + 1, ft); enc_bits(buf, _fl & (uint)((1 << num) - 1), (uint)num); } else { encode(buf, _fl, _fl + 1, _ft + 1); } } internal void enc_bits(Span buf, uint _fl, uint _bits) { uint num = end_window; int num2 = nend_bits; if (num2 + _bits > 32) { do { error |= write_byte_at_end(buf, num & 0xFFu); num >>= 8; num2 -= 8; } while (num2 >= 8); } num |= _fl << num2; num2 += (int)_bits; end_window = num; nend_bits = num2; nbits_total += (int)_bits; } internal void enc_patch_initial_bits(Span buf, uint _val, uint _nbits) { int num = (int)(8 - _nbits); uint num2 = (uint)((1 << (int)_nbits) - 1 << num); if (offs != 0) { buf[0] = (byte)((buf[0] & ~num2) | (_val << num)); } else if (rem >= 0) { rem = (int)((((uint)rem & ~num2) | _val) << num); } else if (rng <= (uint)(int.MinValue >>> (int)_nbits)) { val = (val & ~(num2 << 23)) | (_val << (int)(23L + (long)num)); } else { error = -1; } } internal void enc_shrink(Span buf, uint _size) { Arrays.MemMoveByte(buf, (int)(_size - end_offs), (int)(storage - end_offs), (int)end_offs); storage = _size; } internal uint range_bytes() { return offs; } internal int get_error() { return error; } internal int tell() { return nbits_total - Inlines.EC_ILOG(rng); } internal uint tell_frac() { int num = nbits_total << 3; int num2 = Inlines.EC_ILOG(rng); int num3 = (int)(rng >> num2 - 16); uint num4 = (uint)((num3 >> 12) - 8); num4 += ((num3 > correction[num4]) ? 1u : 0u); num2 = (int)((num2 << 3) + num4); return (uint)(num - num2); } internal void enc_done(Span buf) { int num = 32 - Inlines.EC_ILOG(rng); uint num2 = 2147483647u >> num; uint num3 = (val + num2) & ~num2; if ((num3 | num2) >= val + rng) { num++; num2 >>= 1; num3 = (val + num2) & ~num2; } while (num > 0) { enc_carry_out(buf, (int)(num3 >> 23)); num3 = (num3 << 8) & 0x7FFFFFFFu; num -= 8; } if (rem >= 0 || ext != 0) { enc_carry_out(buf, 0); } uint num4 = end_window; int num5; for (num5 = nend_bits; num5 >= 8; num5 -= 8) { error |= write_byte_at_end(buf, num4 & 0xFFu); num4 >>= 8; } if (error != 0) { return; } Arrays.MemSetWithOffset(buf, 0, (int)offs, (int)(storage - offs - end_offs)); if (num5 <= 0) { return; } if (end_offs >= storage) { error = -1; return; } num = -num; if (offs + end_offs >= storage && num < num5) { num4 &= (uint)((1 << num) - 1); error = -1; } buf[(int)(storage - end_offs - 1)] |= (byte)num4; } } internal static class Inlines { private const MethodImplOptions INLINE_ATTR = MethodImplOptions.AggressiveInlining; private static readonly short[] sqrt_C = new short[5] { 23175, 11561, -3011, 1699, -664 }; private const short log2_C0 = -6793; [Conditional("DEBUG")] internal static void OpusAssert(bool condition, string message = "Unknown error") { } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_16SU(int a, int b) { return (short)a * (ushort)b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_16SU(short a, ushort b) { return a * b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_16SU(int a, uint b) { return a * (int)b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_32_Q16(short a, int b) { return ADD32(MULT16_16(a, SHR(b, 16)), SHR(MULT16_16SU(a, b & 0xFFFF), 16)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_32_Q16(int a, int b) { return ADD32(MULT16_16(a, SHR(b, 16)), SHR(MULT16_16SU(a, b & 0xFFFF), 16)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_32_P16(short a, int b) { return ADD32(MULT16_16(a, SHR(b, 16)), PSHR(MULT16_16SU(a, b & 0xFFFF), 16)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_32_P16(int a, int b) { return ADD32(MULT16_16(a, SHR(b, 16)), PSHR(MULT16_16SU(a, b & 0xFFFF), 16)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_32_Q15(short a, int b) { return (a * (b >> 16) << 1) + (a * (b & 0xFFFF) >> 15); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_32_Q15(int a, int b) { return (a * (b >> 16) << 1) + (a * (b & 0xFFFF) >> 15); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT32_32_Q31(int a, int b) { return ADD32(ADD32(SHL(MULT16_16(SHR(a, 16), SHR(b, 16)), 1), SHR(MULT16_16SU(SHR(a, 16), b & 0xFFFF), 15)), SHR(MULT16_16SU(SHR(b, 16), a & 0xFFFF), 15)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short QCONST16(float x, int bits) { return (short)(0.5 + (double)(x * (float)(1 << bits))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int QCONST32(float x, int bits) { return (int)(0.5 + (double)(x * (float)(1 << bits))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short NEG16(short x) { return (short)(-x); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int NEG16(int x) { return -x; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int NEG32(int x) { return -x; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short EXTRACT16(int x) { return (short)x; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int EXTEND32(short x) { return x; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int EXTEND32(int x) { return x; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short SHR16(short a, int shift) { return (short)(a >> shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int SHR16(int a, int shift) { return a >> shift; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short SHL16(short a, int shift) { return (short)((ushort)a << shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int SHL16(int a, int shift) { return a << shift; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int SHR32(int a, int shift) { return a >> shift; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int SHL32(int a, int shift) { return a << shift; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int PSHR32(int a, int shift) { return SHR32(a + (EXTEND32(1) << shift >> 1), shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short PSHR16(short a, int shift) { return SHR16((short)(a + (1 << shift >> 1)), shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int PSHR16(int a, int shift) { return SHR32(a + (1 << shift >> 1), shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int VSHR32(int a, int shift) { if (shift <= 0) { return SHL32(a, -shift); } return SHR32(a, shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int SHR(int a, int shift) { return a >> shift; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int SHL(int a, int shift) { return SHL32(a, shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int SHR(short a, int shift) { return a >> shift; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int SHL(short a, int shift) { return SHL32(a, shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int PSHR(int a, int shift) { return SHR(a + (EXTEND32(1) << shift >> 1), shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int SATURATE(int x, int a) { if (x <= a) { if (x >= -a) { return x; } return -a; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short SATURATE16(int x) { return EXTRACT16((x > 32767) ? 32767 : ((x < -32768) ? (-32768) : x)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short ROUND16(short x, short a) { return EXTRACT16(PSHR32(x, a)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int ROUND16(int x, int a) { return PSHR32(x, a); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int PDIV32(int a, int b) { return a / b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short HALF16(short x) { return SHR16(x, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int HALF16(int x) { return SHR32(x, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int HALF32(int x) { return SHR32(x, 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short ADD16(short a, short b) { return (short)(a + b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int ADD16(int a, int b) { return a + b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short SUB16(short a, short b) { return (short)(a - b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int SUB16(int a, int b) { return a - b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int ADD32(int a, int b) { return a + b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int SUB32(int a, int b) { return a - b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short MULT16_16_16(short a, short b) { return (short)(a * b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_16_16(int a, int b) { return a * b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_16(int a, int b) { return a * b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_16(short a, short b) { return a * b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MAC16_16(short c, short a, short b) { return c + a * b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MAC16_16(int c, short a, short b) { return c + a * b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MAC16_16(int c, int a, int b) { return c + a * b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MAC16_32_Q15(int c, short a, short b) { return ADD32(c, ADD32(MULT16_16(a, SHR(b, 15)), SHR(MULT16_16(a, b & 0x7FFF), 15))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MAC16_32_Q15(int c, int a, int b) { return ADD32(c, ADD32(MULT16_16(a, SHR(b, 15)), SHR(MULT16_16(a, b & 0x7FFF), 15))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MAC16_32_Q16(int c, short a, short b) { return ADD32(c, ADD32(MULT16_16(a, SHR(b, 16)), SHR(MULT16_16SU(a, b & 0xFFFF), 16))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MAC16_32_Q16(int c, int a, int b) { return ADD32(c, ADD32(MULT16_16(a, SHR(b, 16)), SHR(MULT16_16SU(a, b & 0xFFFF), 16))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_16_Q11_32(short a, short b) { return SHR(MULT16_16(a, b), 11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_16_Q11_32(int a, int b) { return SHR(MULT16_16(a, b), 11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short MULT16_16_Q11(short a, short b) { return (short)SHR(MULT16_16(a, b), 11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_16_Q11(int a, int b) { return SHR(MULT16_16(a, b), 11); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short MULT16_16_Q13(short a, short b) { return (short)SHR(MULT16_16(a, b), 13); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_16_Q13(int a, int b) { return SHR(MULT16_16(a, b), 13); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short MULT16_16_Q14(short a, short b) { return (short)SHR(MULT16_16(a, b), 14); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_16_Q14(int a, int b) { return SHR(MULT16_16(a, b), 14); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short MULT16_16_Q15(short a, short b) { return (short)SHR(MULT16_16(a, b), 15); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_16_Q15(int a, int b) { return SHR(MULT16_16(a, b), 15); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short MULT16_16_P13(short a, short b) { return (short)SHR(ADD32(4096, MULT16_16(a, b)), 13); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_16_P13(int a, int b) { return SHR(ADD32(4096, MULT16_16(a, b)), 13); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short MULT16_16_P14(short a, short b) { return (short)SHR(ADD32(8192, MULT16_16(a, b)), 14); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_16_P14(int a, int b) { return SHR(ADD32(8192, MULT16_16(a, b)), 14); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short MULT16_16_P15(short a, short b) { return (short)SHR(ADD32(16384, MULT16_16(a, b)), 15); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MULT16_16_P15(int a, int b) { return SHR(ADD32(16384, MULT16_16(a, b)), 15); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short DIV32_16(int a, short b) { return (short)(a / b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int DIV32_16(int a, int b) { return a / b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int DIV32(int a, int b) { return a / b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short SAT16(int x) { return (x > 32767) ? short.MaxValue : ((x < -32768) ? short.MinValue : ((short)x)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short SIG2WORD16(int x) { x = PSHR32(x, 12); x = MAX32(x, -32768); x = MIN32(x, 32767); return EXTRACT16(x); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short MIN(short a, short b) { if (a >= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short MAX(short a, short b) { if (a <= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short MIN16(short a, short b) { if (a >= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short MAX16(short a, short b) { if (a <= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MIN16(int a, int b) { if (a >= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MAX16(int a, int b) { if (a <= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static float MIN16(float a, float b) { if (!(a < b)) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static float MAX16(float a, float b) { if (!(a > b)) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MIN(int a, int b) { if (a >= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MAX(int a, int b) { if (a <= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int IMIN(int a, int b) { if (a >= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static uint IMIN(uint a, uint b) { if (a >= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int IMAX(int a, int b) { if (a <= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MIN32(int a, int b) { if (a >= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MAX32(int a, int b) { if (a <= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static float MIN32(float a, float b) { if (!(a < b)) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static float MAX32(float a, float b) { if (!(a > b)) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int ABS16(int x) { if (x >= 0) { return x; } return -x; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static float ABS16(float x) { if (!(x < 0f)) { return x; } return 0f - x; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short ABS16(short x) { return (short)((x < 0) ? (-x) : x); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int ABS32(int x) { if (x >= 0) { return x; } return -x; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static uint celt_udiv(uint n, uint d) { return n / d; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int celt_udiv(int n, int d) { return n / d; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int celt_sudiv(int n, int d) { return n / d; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int celt_div(int a, int b) { return MULT32_32_Q31(a, celt_rcp(b)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int celt_ilog2(int x) { return EC_ILOG((uint)x) - 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int celt_zlog2(int x) { if (x > 0) { return celt_ilog2(x); } return 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int celt_maxabs16(Span x, int x_ptr, int len) { int num = 0; int num2 = 0; for (int i = x_ptr; i < len + x_ptr; i++) { num = MAX32(num, x[i]); num2 = MIN32(num2, x[i]); } return MAX32(EXTEND32(num), -EXTEND32(num2)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int celt_maxabs32(Span x, int len) { int a = 0; int num = 0; for (int i = 0; i < len; i++) { a = MAX32(a, x[i]); num = MIN32(num, x[i]); } return MAX32(a, -num); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int celt_maxabs32(Span x, int x_ptr, int len) { int a = 0; int num = 0; for (int i = x_ptr; i < x_ptr + len; i++) { a = MAX32(a, x[i]); num = MIN32(num, x[i]); } return MAX32(a, -num); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short celt_maxabs32(Span x, int x_ptr, int len) { short a = 0; short num = 0; for (int i = x_ptr; i < x_ptr + len; i++) { a = MAX16(a, x[i]); num = MIN16(num, x[i]); } return MAX(a, (short)(-num)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int FRAC_MUL16(int a, int b) { return 16384 + (short)a * (short)b >> 15; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static uint isqrt32(uint _val) { uint num = 0u; int num2 = EC_ILOG(_val) - 1 >> 1; uint num3 = (uint)(1 << num2); do { uint num4 = (num << 1) + num3 << num2; if (num4 <= _val) { num += num3; _val -= num4; } num3 >>= 1; num2--; } while (num2 >= 0); return num; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int celt_sqrt(int x) { if (x == 0) { return 0; } if (x >= 1073741824) { return 32767; } int num = (celt_ilog2(x) >> 1) - 7; x = VSHR32(x, 2 * num); short a = (short)(x - 32768); return VSHR32(ADD16(sqrt_C[0], MULT16_16_Q15(a, ADD16(sqrt_C[1], MULT16_16_Q15(a, ADD16(sqrt_C[2], MULT16_16_Q15(a, ADD16(sqrt_C[3], MULT16_16_Q15(a, sqrt_C[4])))))))), 7 - num); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int celt_rcp(int x) { int num = celt_ilog2(x); int b = VSHR32(x, num - 15) - 32768; int a = ADD16(30840, MULT16_16_Q15(-15420, b)); a = SUB16(a, MULT16_16_Q15(a, ADD16(MULT16_16_Q15(a, b), ADD16(a, -32768)))); a = SUB16(a, ADD16(1, MULT16_16_Q15(a, ADD16(MULT16_16_Q15(a, b), ADD16(a, -32768))))); return VSHR32(EXTEND32(a), num - 16); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int celt_rsqrt_norm(int x) { int num = x - 32768; int num2 = ADD16(23557, MULT16_16_Q15(num, ADD16(-13490, MULT16_16_Q15(num, 6713)))); int num3 = MULT16_16_Q15(num2, num2); int a = SHL16(SUB16(ADD16(MULT16_16_Q15(num3, num), num3), 16384), 1); return ADD16(num2, MULT16_16_Q15(num2, MULT16_16_Q15(a, SUB16(MULT16_16_Q15(a, 12288), 16384)))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int frac_div32(int a, int b) { int shift = celt_ilog2(b) - 29; a = VSHR32(a, shift); b = VSHR32(b, shift); int a2 = ROUND16(celt_rcp(ROUND16(b, 16)), 3); int a3 = MULT16_32_Q15(a2, a); int b2 = PSHR32(a, 2) - MULT32_32_Q31(a3, b); a3 = ADD32(a3, SHL32(MULT16_32_Q15(a2, b2), 2)); if (a3 >= 536870912) { return int.MaxValue; } if (a3 <= -536870912) { return -2147483647; } return SHL32(a3, 2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int celt_log2(int x) { if (x == 0) { return -32767; } int num = celt_ilog2(x); int a = VSHR32(x, num - 15) - 32768 - 16384; int a2 = ADD16(-6793, MULT16_16_Q15(a, ADD16(15746, MULT16_16_Q15(a, ADD16(-5217, MULT16_16_Q15(a, ADD16(2545, MULT16_16_Q15(a, -1401)))))))); return SHL16((short)(num - 13), 10) + SHR16(a2, 4); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int celt_exp2_frac(int x) { int num = SHL16(x, 4); return ADD16(16383, MULT16_16_Q15(num, ADD16(22804, MULT16_16_Q15(num, ADD16(14819, MULT16_16_Q15(10204, num)))))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int celt_exp2(int x) { int num = SHR16(x, 10); if (num > 14) { return 2130706432; } if (num < -15) { return 0; } return VSHR32(EXTEND32((int)(short)celt_exp2_frac((short)(x - SHL16((short)num, 10)))), -num - 2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int celt_atan01(int x) { return MULT16_16_P15(x, ADD32(32767, MULT16_16_P15(x, ADD32(-21, MULT16_16_P15(x, ADD32(-11943, MULT16_16_P15(4936, x))))))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int celt_atan2p(int y, int x) { if (y < x) { int num = celt_div(SHL32(EXTEND32(y), 15), x); if (num >= 32767) { num = 32767; } return SHR32(celt_atan01(EXTRACT16(num)), 1); } int num2 = celt_div(SHL32(EXTEND32(x), 15), y); if (num2 >= 32767) { num2 = 32767; } return 25736 - SHR16(celt_atan01(EXTRACT16(num2)), 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int celt_cos_norm(int x) { x &= 0x1FFFF; if (x > SHL32(EXTEND32(1), 16)) { x = SUB32(SHL32(EXTEND32(1), 17), x); } if (((uint)x & 0x7FFFu) != 0) { if (x < SHL32(EXTEND32(1), 15)) { return _celt_cos_pi_2(EXTRACT16(x)); } return NEG32(_celt_cos_pi_2(EXTRACT16(65536 - x))); } if (((uint)x & 0xFFFFu) != 0) { return 0; } if (((uint)x & 0x1FFFFu) != 0) { return -32767; } return 32767; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int _celt_cos_pi_2(int x) { int num = MULT16_16_P15(x, x); return ADD32(1, MIN32(32766, ADD32(SUB16(32767, num), MULT16_16_P15(num, ADD32(-7651, MULT16_16_P15(num, ADD32(8277, MULT16_16_P15(-626, num)))))))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short FLOAT2INT16(float x) { x *= 32768f; if (x < -32768f) { x = -32768f; } if (x > 32767f) { x = 32767f; } return (short)x; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_ROR32(int a32, int rot) { return (int)silk_ROR32((uint)a32, rot); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static uint silk_ROR32(uint a32, int rot) { int num = -rot; if (rot == 0) { return a32; } if (rot < 0) { return (a32 << num) | (a32 >> 32 - num); } return (a32 << 32 - rot) | (a32 >> rot); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_MUL(int a32, int b32) { return a32 * b32; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static uint silk_MUL_uint(uint a32, uint b32) { return a32 * b32; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_MLA(int a32, int b32, int c32) { return silk_ADD32(a32, b32 * c32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_MLA_uint(uint a32, uint b32, uint c32) { return (int)silk_ADD32(a32, b32 * c32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SMULTT(int a32, int b32) { return (a32 >> 16) * (b32 >> 16); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SMLATT(int a32, int b32, int c32) { return silk_ADD32(a32, (b32 >> 16) * (c32 >> 16)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long silk_SMLALBB(long a64, short b16, short c16) { return silk_ADD64(a64, b16 * c16); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long silk_SMULL(int a32, int b32) { return (long)a32 * (long)b32; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_ADD32_ovflw(int a, int b) { return a + b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_ADD32_ovflw(uint a, uint b) { return (int)(a + b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SUB32_ovflw(int a, int b) { return a - b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_MLA_ovflw(int a32, int b32, int c32) { return silk_ADD32_ovflw((uint)a32, (uint)(b32 * c32)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SMLABB_ovflw(int a32, int b32, int c32) { return silk_ADD32_ovflw(a32, (short)b32 * (short)c32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SMULBB(int a32, int b32) { return (short)a32 * (short)b32; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SMULWB(int a32, int b32) { return (int)((long)a32 * (long)(short)b32 >> 16); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SMLABB(int a32, int b32, int c32) { return a32 + (short)b32 * (short)c32; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_DIV32_16(int a32, int b32) { return a32 / b32; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_DIV32(int a32, int b32) { return a32 / b32; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short silk_ADD16(short a, short b) { return (short)(a + b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_ADD32(int a, int b) { return a + b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static uint silk_ADD32(uint a, uint b) { return a + b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long silk_ADD64(long a, long b) { return a + b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short silk_SUB16(short a, short b) { return (short)(a - b); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SUB32(int a, int b) { return a - b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long silk_SUB64(long a, long b) { return a - b; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SAT8(int a) { if (a <= 255) { if (a >= 0) { return a; } return 0; } return 255; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SAT16(int a) { if (a <= 32767) { if (a >= -32768) { return a; } return -32768; } return 32767; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SAT32(long a) { if (a <= int.MaxValue) { if (a >= int.MinValue) { return (int)a; } return int.MinValue; } return int.MaxValue; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short silk_ADD_SAT16(short a16, short b16) { return (short)silk_SAT16(silk_ADD32(a16, b16)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_ADD_SAT32(int a32, int b32) { if (((uint)(a32 + b32) & 0x80000000u) != 0) { if (((a32 | b32) & 0x80000000u) != 0L) { return a32 + b32; } return int.MaxValue; } if ((a32 & b32 & 0x80000000u) == 0L) { return a32 + b32; } return int.MinValue; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long silk_ADD_SAT64(long a64, long b64) { if (((a64 + b64) & long.MinValue) != 0L) { if (((a64 | b64) & long.MinValue) != 0L) { return a64 + b64; } return long.MaxValue; } if ((a64 & b64 & long.MinValue) == 0L) { return a64 + b64; } return long.MinValue; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short silk_SUB_SAT16(short a16, short b16) { return (short)silk_SAT16(silk_SUB32(a16, b16)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SUB_SAT32(int a32, int b32) { if (((uint)(a32 - b32) & 0x80000000u) != 0) { if (((a32 ^ 0x80000000u) & b32 & 0x80000000u) == 0L) { return a32 - b32; } return int.MaxValue; } if ((a32 & (b32 ^ 0x80000000u) & 0x80000000u) == 0L) { return a32 - b32; } return int.MinValue; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long silk_SUB_SAT64(long a64, long b64) { if (((a64 - b64) & long.MinValue) != 0L) { if (((a64 ^ long.MinValue) & b64 & long.MinValue) == 0L) { return a64 - b64; } return long.MaxValue; } if ((a64 & (b64 ^ long.MinValue) & long.MinValue) == 0L) { return a64 - b64; } return long.MinValue; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static sbyte silk_ADD_POS_SAT8(sbyte a, sbyte b) { return (sbyte)((((uint)(a + b) & 0x80u) != 0) ? 127 : (a + b)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short silk_ADD_POS_SAT16(short a, short b) { return (short)((((uint)(a + b) & 0x8000u) != 0) ? 32767 : (a + b)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_ADD_POS_SAT32(int a, int b) { if (((a + b) & 0x80000000u) == 0L) { return a + b; } return int.MaxValue; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long silk_ADD_POS_SAT64(long a, long b) { if (((a + b) & long.MinValue) == 0L) { return a + b; } return long.MaxValue; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static sbyte silk_LSHIFT8(sbyte a, int shift) { return (sbyte)(a << shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short silk_LSHIFT16(short a, int shift) { return (short)(a << shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_LSHIFT32(int a, int shift) { return a << shift; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long silk_LSHIFT64(long a, int shift) { return a << shift; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_LSHIFT(int a, int shift) { return a << shift; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_LSHIFT_ovflw(int a, int shift) { return a << shift; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static uint silk_LSHIFT_uint(uint a, int shift) { return a << shift; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_LSHIFT_SAT32(int a, int shift) { return silk_LSHIFT32(silk_LIMIT(a, silk_RSHIFT32(int.MinValue, shift), silk_RSHIFT32(int.MaxValue, shift)), shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static sbyte silk_RSHIFT8(sbyte a, int shift) { return (sbyte)(a >> shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short silk_RSHIFT16(short a, int shift) { return (short)(a >> shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_RSHIFT32(int a, int shift) { return a >> shift; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_RSHIFT(int a, int shift) { return a >> shift; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long silk_RSHIFT64(long a, int shift) { return a >> shift; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static uint silk_RSHIFT_uint(uint a, int shift) { return a >> shift; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_ADD_LSHIFT(int a, int b, int shift) { return a + (b << shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_ADD_LSHIFT32(int a, int b, int shift) { return a + (b << shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static uint silk_ADD_LSHIFT_uint(uint a, uint b, int shift) { return a + (b << shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_ADD_RSHIFT(int a, int b, int shift) { return a + (b >> shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_ADD_RSHIFT32(int a, int b, int shift) { return a + (b >> shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static uint silk_ADD_RSHIFT_uint(uint a, uint b, int shift) { return a + (b >> shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SUB_LSHIFT32(int a, int b, int shift) { return a - (b << shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SUB_RSHIFT32(int a, int b, int shift) { return a - (b >> shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_RSHIFT_ROUND(int a, int shift) { if (shift != 1) { return (a >> shift - 1) + 1 >> 1; } return (a >> 1) + (a & 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long silk_RSHIFT_ROUND64(long a, int shift) { if (shift != 1) { return (a >> shift - 1) + 1 >> 1; } return (a >> 1) + (a & 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_min(int a, int b) { if (a >= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_max(int a, int b) { if (a <= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static float silk_min(float a, float b) { if (!(a < b)) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static float silk_max(float a, float b) { if (!(a > b)) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int SILK_CONST(float number, int scale) { return (int)((double)(number * (float)(1L << scale)) + 0.5); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_min_int(int a, int b) { if (a >= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short silk_min_16(short a, short b) { if (a >= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_min_32(int a, int b) { if (a >= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long silk_min_64(long a, long b) { if (a >= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_max_int(int a, int b) { if (a <= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short silk_max_16(short a, short b) { if (a <= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_max_32(int a, int b) { if (a <= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long silk_max_64(long a, long b) { if (a <= b) { return b; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static float silk_LIMIT(float a, float limit1, float limit2) { if (!(limit1 > limit2)) { if (!(a > limit2)) { if (!(a < limit1)) { return a; } return limit1; } return limit2; } if (!(a > limit1)) { if (!(a < limit2)) { return a; } return limit2; } return limit1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_LIMIT(int a, int limit1, int limit2) { return silk_LIMIT_32(a, limit1, limit2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_LIMIT_int(int a, int limit1, int limit2) { return silk_LIMIT_32(a, limit1, limit2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static short silk_LIMIT_16(short a, short limit1, short limit2) { if (limit1 <= limit2) { if (a <= limit2) { if (a >= limit1) { return a; } return limit1; } return limit2; } if (a <= limit1) { if (a >= limit2) { return a; } return limit2; } return limit1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_LIMIT_32(int a, int limit1, int limit2) { if (limit1 <= limit2) { if (a <= limit2) { if (a >= limit1) { return a; } return limit1; } return limit2; } if (a <= limit1) { if (a >= limit2) { return a; } return limit2; } return limit1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_abs(int a) { if (a <= 0) { return -a; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_abs_int16(int a) { return (a ^ (a >> 15)) - (a >> 15); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_abs_int32(int a) { return (a ^ (a >> 31)) - (a >> 31); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long silk_abs_int64(long a) { if (a <= 0) { return -a; } return a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long silk_sign(int a) { return (a > 0) ? 1 : ((a < 0) ? (-1) : 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_RAND(int seed) { return silk_MLA_ovflw(907633515, seed, 196314165); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SMMUL(int a32, int b32) { return (int)silk_RSHIFT64(silk_SMULL(a32, b32), 32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SMLAWT(int a32, int b32, int c32) { return a32 + (b32 >> 16) * (c32 >> 16) + ((b32 & 0xFFFF) * (c32 >> 16) >> 16); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_DIV32_varQ(int a32, int b32, int Qres) { int num = silk_CLZ32(silk_abs(a32)) - 1; int num2 = silk_LSHIFT(a32, num); int num3 = silk_CLZ32(silk_abs(b32)) - 1; int num4 = silk_LSHIFT(b32, num3); int num5 = silk_DIV32_16(536870911, silk_RSHIFT(num4, 16)); int num6 = silk_SMULWB(num2, num5); num2 = silk_SUB32_ovflw(num2, silk_LSHIFT_ovflw(silk_SMMUL(num4, num6), 3)); num6 = silk_SMLAWB(num6, num2, num5); int num7 = 29 + num - num3 - Qres; if (num7 < 0) { return silk_LSHIFT_SAT32(num6, -num7); } if (num7 < 32) { return silk_RSHIFT(num6, num7); } return 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_INVERSE32_varQ(int b32, int Qres) { int num = silk_CLZ32(silk_abs(b32)) - 1; int num2 = silk_LSHIFT(b32, num); int num3 = silk_DIV32_16(536870911, (short)silk_RSHIFT(num2, 16)); int a = silk_LSHIFT(num3, 16); int b33 = silk_LSHIFT(536870912 - silk_SMULWB(num2, num3), 3); a = silk_SMLAWW(a, b33, num3); int num4 = 61 - num - Qres; if (num4 <= 0) { return silk_LSHIFT_SAT32(a, -num4); } if (num4 < 32) { return silk_RSHIFT(a, num4); } return 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SMLAWB(int a32, int b32, int c32) { return a32 + silk_SMULWB(b32, c32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SMULWT(int a32, int b32) { return (a32 >> 16) * (b32 >> 16) + ((a32 & 0xFFFF) * (b32 >> 16) >> 16); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SMULBT(int a32, int b32) { return (short)a32 * (b32 >> 16); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SMLABT(int a32, int b32, int c32) { return a32 + (short)b32 * (c32 >> 16); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long silk_SMLAL(long a64, int b32, int c32) { return silk_ADD64(a64, (long)b32 * (long)c32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void MatrixSet(T[] Matrix_base_adr, int Matrix_ptr, int row, int column, int N, T value) { Matrix_base_adr[Matrix_ptr + row * N + column] = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MatrixGetPointer(int row, int column, int N) { return row * N + column; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static T MatrixGet(T[] Matrix_base_adr, int row, int column, int N) { return Matrix_base_adr[row * N + column]; } internal static T MatrixGet(T[] Matrix_base_adr, int matrix_ptr, int row, int column, int N) { return Matrix_base_adr[matrix_ptr + row * N + column]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void MatrixSet(T[] Matrix_base_adr, int row, int column, int N, T value) { Matrix_base_adr[row * N + column] = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SMULWW(int a32, int b32) { return silk_MLA(silk_SMULWB(a32, b32), a32, silk_RSHIFT_ROUND(b32, 16)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SMLAWW(int a32, int b32, int c32) { return silk_MLA(silk_SMLAWB(a32, b32, c32), b32, silk_RSHIFT_ROUND(c32, 16)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_CLZ64(long input) { int num = (int)silk_RSHIFT64(input, 32); if (num == 0) { return 32 + silk_CLZ32((int)input); } return silk_CLZ32(num); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_CLZ32(int in32) { if (in32 != 0) { return 32 - EC_ILOG((uint)in32); } return 32; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void silk_CLZ_FRAC(int input, out int lz, out int frac_Q7) { frac_Q7 = silk_ROR32(input, 24 - (lz = silk_CLZ32(input))) & 0x7F; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_SQRT_APPROX(int x) { if (x <= 0) { return 0; } silk_CLZ_FRAC(x, out var lz, out var frac_Q); int num = (((lz & 1) == 0) ? 46214 : 32768); num >>= silk_RSHIFT(lz, 1); return silk_SMLAWB(num, num, silk_SMULBB(213, frac_Q)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int MUL32_FRAC_Q(int a32, int b32, int Q) { return (int)silk_RSHIFT_ROUND64(silk_SMULL(a32, b32), Q); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_lin2log(int inLin) { silk_CLZ_FRAC(inLin, out var lz, out var frac_Q); return silk_LSHIFT(31 - lz, 7) + silk_SMLAWB(frac_Q, silk_MUL(frac_Q, 128 - frac_Q), 179); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_log2lin(int inLog_Q7) { if (inLog_Q7 < 0) { return 0; } if (inLog_Q7 >= 3967) { return int.MaxValue; } int num = silk_LSHIFT(1, silk_RSHIFT(inLog_Q7, 7)); int num2 = inLog_Q7 & 0x7F; if (inLog_Q7 < 2048) { return silk_ADD_RSHIFT32(num, silk_MUL(num, silk_SMLAWB(num2, silk_SMULBB(num2, 128 - num2), -174)), 7); } return silk_MLA(num, silk_RSHIFT(num, 7), silk_SMLAWB(num2, silk_SMULBB(num2, 128 - num2), -174)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void silk_interpolate(short[] xi, short[] x0, short[] x1, int ifact_Q2, int d) { for (int i = 0; i < d; i++) { xi[i] = (short)silk_ADD_RSHIFT(x0[i], silk_SMULBB(x1[i] - x0[i], ifact_Q2), 2); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_inner_prod_aligned_scale(short[] inVec1, short[] inVec2, int scale, int len) { int num = 0; for (int i = 0; i < len; i++) { num = silk_ADD_RSHIFT32(num, silk_SMULBB(inVec1[i], inVec2[i]), scale); } return num; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void silk_scale_copy_vector16(Span data_out, int data_out_ptr, Span data_in, int data_in_ptr, int gain_Q16, int dataSize) { for (int i = 0; i < dataSize; i++) { data_out[data_out_ptr + i] = (short)silk_SMULWB(gain_Q16, data_in[data_in_ptr + i]); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void silk_scale_vector32_Q26_lshift_18(int[] data1, int data1_ptr, int gain_Q26, int dataSize) { for (int i = data1_ptr; i < data1_ptr + dataSize; i++) { data1[i] = (int)silk_RSHIFT64(silk_SMULL(data1[i], gain_Q26), 8); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_inner_prod(short[] inVec1, int inVec1_ptr, short[] inVec2, int inVec2_ptr, int len) { int num = 0; for (int i = 0; i < len; i++) { num = MAC16_16(num, inVec1[inVec1_ptr + i], inVec2[inVec2_ptr + i]); } return num; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int silk_inner_prod_self(short[] inVec, int inVec_ptr, int len) { int num = 0; for (int i = inVec_ptr; i < inVec_ptr + len; i++) { num = MAC16_16(num, inVec[i], inVec[i]); } return num; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static long silk_inner_prod16_aligned_64(short[] inVec1, int inVec1_ptr, short[] inVec2, int inVec2_ptr, int len) { long num = 0L; for (int i = 0; i < len; i++) { num = silk_SMLALBB(num, inVec1[inVec1_ptr + i], inVec2[inVec2_ptr + i]); } return num; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static uint EC_MINI(uint a, uint b) { return a + ((b - a) & (uint)((b < a) ? (-1) : 0)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int EC_CLZ(uint x) { if (x == 0) { return 0; } x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; uint num = x - ((x >> 1) & 0x55555555); num = ((num >> 2) & 0x33333333) + (num & 0x33333333); num = ((num >> 4) + num) & 0xF0F0F0Fu; num += num >> 8; num += num >> 16; num &= 0x3Fu; return (int)(1 - num); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int EC_ILOG(uint x) { if (x == 0) { return 1; } x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; uint num = x - ((x >> 1) & 0x55555555); num = ((num >> 2) & 0x33333333) + (num & 0x33333333); num = ((num >> 4) + num) & 0xF0F0F0Fu; num += num >> 8; num += num >> 16; return (int)(num & 0x3F); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int abs(int a) { if (a < 0) { return -a; } return a; } } public class SpeexResampler : IResampler, IDisposable { private class FuncDef { public double[] table; public int oversample; public static readonly double[] kaiser12_table = new double[68] { 0.99859849, 1.0, 0.99859849, 0.99440475, 0.98745105, 0.97779076, 0.9654977, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014, 0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.7262997, 0.69451601, 0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014, 0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.343018, 0.3150649, 0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546, 0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178, 0.0706395, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947, 0.02584161, 0.02127838, 0.0173625, 0.01402878, 0.01121463, 0.00886058, 0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438, 0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 5.27734E-05, 1E-05, 0.0 }; public static readonly double[] kaiser10_table = new double[36] { 0.99537781, 1.0, 0.99537781, 0.98162644, 0.95908712, 0.92831446, 0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347, 0.56155915, 0.5011968, 0.44221549, 0.38553619, 0.33194107, 0.28205962, 0.23636152, 0.19515633, 0.15859932, 0.1267028, 0.09935205, 0.07632451, 0.05731132, 0.0419398, 0.02979584, 0.0204451, 0.01345224, 0.00839739, 0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.0, 0.0 }; public static readonly double[] kaiser8_table = new double[36] { 0.99635258, 1.0, 0.99635258, 0.98548012, 0.96759014, 0.943022, 0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126, 0.6345175, 0.58014482, 0.52566725, 0.47185369, 0.4194115, 0.36897272, 0.32108304, 0.27619388, 0.23465776, 0.1967267, 0.1625538, 0.13219758, 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.0236949, 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.0005, 0.0 }; public static readonly double[] kaiser6_table = new double[36] { 0.99733006, 1.0, 0.99733006, 0.98935595, 0.97618418, 0.95799003, 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565, 0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561, 0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058, 0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.0869312, 0.067226, 0.0503182, 0.03607231, 0.02432151, 0.01487334, 0.00752, 0.0 }; public FuncDef(double[] t, int os) { table = t; oversample = os; } } private class QualityMapping { public int base_length; public int oversample; public float downsample_bandwidth; public float upsample_bandwidth; public FuncDef window_func; public static readonly QualityMapping[] quality_map = new QualityMapping[11] { new QualityMapping(8, 4, 0.83f, 0.86f, new FuncDef(FuncDef.kaiser6_table, 32)), new QualityMapping(16, 4, 0.85f, 0.88f, new FuncDef(FuncDef.kaiser6_table, 32)), new QualityMapping(32, 4, 0.882f, 0.91f, new FuncDef(FuncDef.kaiser6_table, 32)), new QualityMapping(48, 8, 0.895f, 0.917f, new FuncDef(FuncDef.kaiser8_table, 32)), new QualityMapping(64, 8, 0.921f, 0.94f, new FuncDef(FuncDef.kaiser8_table, 32)), new QualityMapping(80, 16, 0.922f, 0.94f, new FuncDef(FuncDef.kaiser10_table, 32)), new QualityMapping(96, 16, 0.94f, 0.945f, new FuncDef(FuncDef.kaiser10_table, 32)), new QualityMapping(128, 16, 0.95f, 0.95f, new FuncDef(FuncDef.kaiser10_table, 32)), new QualityMapping(160, 16, 0.96f, 0.96f, new FuncDef(FuncDef.kaiser10_table, 32)), new QualityMapping(192, 32, 0.968f, 0.968f, new FuncDef(FuncDef.kaiser12_table, 64)), new QualityMapping(256, 32, 0.975f, 0.975f, new FuncDef(FuncDef.kaiser12_table, 64)) }; private QualityMapping(int bl, int os, float dsb, float usb, FuncDef wf) { base_length = bl; oversample = os; downsample_bandwidth = dsb; upsample_bandwidth = usb; window_func = wf; } } private delegate int resampler_basic_func(int channel_index, Span input, int input_ptr, ref int in_len, Span output, int output_ptr, ref int out_len); private const int FIXED_STACK_ALLOC = 8192; private int in_rate; private int out_rate; private int num_rate; private int den_rate; private int quality; private int nb_channels; private int filt_len; private int mem_alloc_size; private int buffer_size; private int int_advance; private int frac_advance; private float cutoff; private int oversample; private int initialised; private int started; private int[] last_sample; private int[] samp_frac_num; private int[] magic_samples; private float[] mem; private float[] sinc_table; private int sinc_table_length; private resampler_basic_func resampler_ptr; private int in_stride; private int out_stride; public int Quality { get { return quality; } set { if (value > 10 || value < 0) { throw new ArgumentException("Quality must be between 0 and 10"); } if (quality != value) { quality = value; if (initialised != 0) { update_filter(); } } } } public int InputStride { get { return in_stride; } set { in_stride = value; } } public int OutputStride { get { return out_stride; } set { out_stride = value; } } public int InputLatency => filt_len / 2; public int OutputLatencySamples => (filt_len / 2 * den_rate + (num_rate >> 1)) / num_rate; public TimeSpan OutputLatency => TimeSpan.FromTicks((long)OutputLatencySamples * 10000000L / out_rate); private static short FLOAT2INT(float x) { if (!(x < -32768f)) { if (!(x > 32767f)) { return (short)x; } return short.MaxValue; } return short.MinValue; } private static double compute_func(float x, FuncDef func) { float num = x * (float)func.oversample; int num2 = (int)Math.Floor(num); float num3 = num - (float)num2; double num4 = -0.1666666667 * (double)num3 + 0.1666666667 * (double)(num3 * num3 * num3); double num5 = (double)num3 + 0.5 * (double)(num3 * num3) - 0.5 * (double)(num3 * num3 * num3); double num6 = -0.3333333333 * (double)num3 + 0.5 * (double)(num3 * num3) - 0.1666666667 * (double)(num3 * num3 * num3); double num7 = 1.0 - num4 - num5 - num6; return num6 * func.table[num2] + num7 * func.table[num2 + 1] + num5 * func.table[num2 + 2] + num4 * func.table[num2 + 3]; } private static float sinc(float cutoff, float x, int N, FuncDef window_func) { float num = x * cutoff; if (Math.Abs(x) < 1E-06f) { return cutoff; } if (Math.Abs(x) > 0.5f * (float)N) { return 0f; } return (float)((double)cutoff * Math.Sin(Math.PI * (double)num) / (Math.PI * (double)num) * compute_func(Math.Abs(2f * x / (float)N), window_func)); } private static void cubic_coef(float frac, Span interp) { interp[0] = -0.16667f * frac + 0.16667f * frac * frac * frac; interp[1] = frac + 0.5f * frac * frac - 0.5f * frac * frac * frac; interp[3] = -0.33333f * frac + 0.5f * frac * frac - 0.16667f * frac * frac * frac; interp[2] = 1f - interp[0] - interp[1] - interp[3]; } private int resampler_basic_direct_single(int channel_index, Span input, int input_ptr, ref int in_len, Span output, int output_ptr, ref int out_len) { int num = filt_len; int num2 = 0; int num3 = last_sample[channel_index]; int num4 = samp_frac_num[channel_index]; while (num3 < in_len && num2 < out_len) { int num5 = num4 * num; int num6 = input_ptr + num3; float num7 = 0f; for (int i = 0; i < num; i++) { num7 += sinc_table[num5 + i] * input[num6 + i]; } output[output_ptr + out_stride * num2++] = num7; num3 += int_advance; num4 += frac_advance; if (num4 >= den_rate) { num4 -= den_rate; num3++; } } last_sample[channel_index] = num3; samp_frac_num[channel_index] = num4; return num2; } private int resampler_basic_interpolate_single(int channel_index, Span input, int input_ptr, ref int in_len, Span output, int output_ptr, ref int out_len) { int num = filt_len; int num2 = 0; int num3 = last_sample[channel_index]; int num4 = samp_frac_num[channel_index]; Span interp = stackalloc float[4]; Span span = stackalloc float[4]; while (num3 < in_len && num2 < out_len) { int num5 = input_ptr + num3; int num6 = num4 * oversample / den_rate; float frac = (float)(num4 * oversample % den_rate) / (float)den_rate; span[0] = 0f; span[1] = 0f; span[2] = 0f; span[3] = 0f; for (int i = 0; i < num; i++) { float num7 = input[num5 + i]; span[0] += num7 * sinc_table[4 + (i + 1) * oversample - num6 - 2]; span[1] += num7 * sinc_table[4 + (i + 1) * oversample - num6 - 1]; span[2] += num7 * sinc_table[4 + (i + 1) * oversample - num6]; span[3] += num7 * sinc_table[4 + (i + 1) * oversample - num6 + 1]; } cubic_coef(frac, interp); float num8 = interp[0] * span[0] + interp[1] * span[1] + interp[2] * span[2] + interp[3] * span[3]; output[output_ptr + out_stride * num2++] = num8; num3 += int_advance; num4 += frac_advance; if (num4 >= den_rate) { num4 -= den_rate; num3++; } } last_sample[channel_index] = num3; samp_frac_num[channel_index] = num4; return num2; } private void update_filter() { int num = filt_len; oversample = QualityMapping.quality_map[quality].oversample; filt_len = QualityMapping.quality_map[quality].base_length; if (num_rate > den_rate) { cutoff = QualityMapping.quality_map[quality].downsample_bandwidth * (float)den_rate / (float)num_rate; filt_len = filt_len * num_rate / den_rate; filt_len = ((filt_len - 1) & -8) + 8; if (2 * den_rate < num_rate) { oversample >>= 1; } if (4 * den_rate < num_rate) { oversample >>= 1; } if (8 * den_rate < num_rate) { oversample >>= 1; } if (16 * den_rate < num_rate) { oversample >>= 1; } if (oversample < 1) { oversample = 1; } } else { cutoff = QualityMapping.quality_map[quality].upsample_bandwidth; } if (den_rate <= 16 * (oversample + 8)) { if (sinc_table == null) { sinc_table = new float[filt_len * den_rate]; } else if (sinc_table_length < filt_len * den_rate) { sinc_table = new float[filt_len * den_rate]; sinc_table_length = filt_len * den_rate; } for (int i = 0; i < den_rate; i++) { for (int j = 0; j < filt_len; j++) { sinc_table[i * filt_len + j] = sinc(cutoff, (float)(j - filt_len / 2 + 1) - (float)i / (float)den_rate, filt_len, QualityMapping.quality_map[quality].window_func); } } resampler_ptr = resampler_basic_direct_single; } else { if (sinc_table == null) { sinc_table = new float[filt_len * oversample + 8]; } else if (sinc_table_length < filt_len * oversample + 8) { sinc_table = new float[filt_len * oversample + 8]; sinc_table_length = filt_len * oversample + 8; } for (int k = -4; k < oversample * filt_len + 4; k++) { sinc_table[k + 4] = sinc(cutoff, (float)k / (float)oversample - (float)(filt_len / 2), filt_len, QualityMapping.quality_map[quality].window_func); } resampler_ptr = resampler_basic_interpolate_single; } int_advance = num_rate / den_rate; frac_advance = num_rate % den_rate; if (mem == null) { mem_alloc_size = filt_len - 1 + buffer_size; mem = new float[nb_channels * mem_alloc_size]; for (int l = 0; l < nb_channels * mem_alloc_size; l++) { mem[l] = 0f; } } else if (started == 0) { mem_alloc_size = filt_len - 1 + buffer_size; mem = new float[nb_channels * mem_alloc_size]; for (int m = 0; m < nb_channels * mem_alloc_size; m++) { mem[m] = 0f; } } else if (filt_len > num) { int num2 = mem_alloc_size; if (filt_len - 1 + buffer_size > mem_alloc_size) { mem_alloc_size = filt_len - 1 + buffer_size; mem = new float[nb_channels * mem_alloc_size]; } for (int num3 = nb_channels - 1; num3 >= 0; num3--) { int num4 = num; num4 = num + 2 * magic_samples[num3]; for (int num5 = num - 2 + magic_samples[num3]; num5 >= 0; num5--) { mem[num3 * mem_alloc_size + num5 + magic_samples[num3]] = mem[num3 * num2 + num5]; } for (int num5 = 0; num5 < magic_samples[num3]; num5++) { mem[num3 * mem_alloc_size + num5] = 0f; } magic_samples[num3] = 0; if (filt_len > num4) { int num5; for (num5 = 0; num5 < num4 - 1; num5++) { mem[num3 * mem_alloc_size + (filt_len - 2 - num5)] = mem[num3 * mem_alloc_size + (num4 - 2 - num5)]; } for (; num5 < filt_len - 1; num5++) { mem[num3 * mem_alloc_size + (filt_len - 2 - num5)] = 0f; } last_sample[num3] += (filt_len - num4) / 2; } else { magic_samples[num3] = (num4 - filt_len) / 2; for (int num5 = 0; num5 < filt_len - 1 + magic_samples[num3]; num5++) { mem[num3 * mem_alloc_size + num5] = mem[num3 * mem_alloc_size + num5 + magic_samples[num3]]; } } } } else { if (filt_len >= num) { return; } for (int n = 0; n < nb_channels; n++) { int num6 = magic_samples[n]; magic_samples[n] = (num - filt_len) / 2; for (int num7 = 0; num7 < filt_len - 1 + magic_samples[n] + num6; num7++) { mem[n * mem_alloc_size + num7] = mem[n * mem_alloc_size + num7 + magic_samples[n]]; } magic_samples[n] += num6; } } } private void speex_resampler_process_native(int channel_index, ref int in_len, Span output, int output_ptr, ref int out_len) { int num = 0; int num2 = filt_len; int num3 = 0; int num4 = channel_index * mem_alloc_size; started = 1; num3 = resampler_ptr(channel_index, mem, num4, ref in_len, output, output_ptr, ref out_len); if (last_sample[channel_index] < in_len) { in_len = last_sample[channel_index]; } out_len = num3; last_sample[channel_index] -= in_len; int num5 = in_len; for (num = num4; num < num2 - 1 + num4; num++) { mem[num] = mem[num + num5]; } } private int speex_resampler_magic(int channel_index, Span output, ref int output_ptr, int out_len) { int in_len = magic_samples[channel_index]; int num = channel_index * mem_alloc_size; int num2 = filt_len; speex_resampler_process_native(channel_index, ref in_len, output, output_ptr, ref out_len); magic_samples[channel_index] -= in_len; if (magic_samples[channel_index] != 0) { for (int i = num; i < magic_samples[channel_index] + num; i++) { mem[num2 - 1 + i] = mem[num2 - 1 + i + in_len]; } } output_ptr += out_len * out_stride; return out_len; } [Obsolete("Use ResamplerFactory.CreateResampler instead")] public SpeexResampler(int nb_channels, int in_rate, int out_rate, int quality) : this(nb_channels, in_rate, out_rate, in_rate, out_rate, quality) { } [Obsolete("Use ResamplerFactory.CreateResampler instead")] public SpeexResampler(int nb_channels, int ratio_num, int ratio_den, int in_rate, int out_rate, int quality) { if (quality > 10 || quality < 0) { throw new ArgumentException("Quality must be between 0 and 10"); } initialised = 0; started = 0; this.in_rate = 0; this.out_rate = 0; num_rate = 0; den_rate = 0; this.quality = -1; sinc_table_length = 0; mem_alloc_size = 0; filt_len = 0; mem = null; resampler_ptr = null; cutoff = 1f; this.nb_channels = nb_channels; in_stride = 1; out_stride = 1; buffer_size = 160; last_sample = new int[nb_channels]; magic_samples = new int[nb_channels]; samp_frac_num = new int[nb_channels]; for (int i = 0; i < nb_channels; i++) { last_sample[i] = 0; magic_samples[i] = 0; samp_frac_num[i] = 0; } Quality = quality; SetRateFraction(ratio_num, ratio_den, in_rate, out_rate); update_filter(); initialised = 1; } public void Process(int channel_index, Span input, ref int in_len, Span output, ref int out_len) { Process(channel_index, input, 0, ref in_len, output, 0, ref out_len); } private void Process(int channel_index, Span input, int input_ptr, ref int in_len, Span output, int output_ptr, ref int out_len) { int num = in_len; int num2 = out_len; int num3 = channel_index * mem_alloc_size; int num4 = filt_len - 1; int num5 = mem_alloc_size - num4; int num6 = in_stride; if (magic_samples[channel_index] != 0) { num2 -= speex_resampler_magic(channel_index, output, ref output_ptr, num2); } if (magic_samples[channel_index] == 0) { while (num != 0 && num2 != 0) { int in_len2 = ((num > num5) ? num5 : num); int out_len2 = num2; if (input != null) { for (int i = 0; i < in_len2; i++) { mem[num3 + i + num4] = input[input_ptr + i * num6]; } } else { for (int i = 0; i < in_len2; i++) { mem[num3 + i + num4] = 0f; } } speex_resampler_process_native(channel_index, ref in_len2, output, output_ptr, ref out_len2); num -= in_len2; num2 -= out_len2; output_ptr += out_len2 * out_stride; if (input != null) { input_ptr += in_len2 * num6; } } } in_len -= num; out_len -= num2; } public void Process(int channel_index, Span input, ref int in_len, Span output, ref int out_len) { Process(channel_index, input, 0, ref in_len, output, 0, ref out_len); } private void Process(int channel_index, Span input, int input_ptr, ref int in_len, Span output, int output_ptr, ref int out_len) { int num = in_stride; int num2 = out_stride; int num3 = in_len; int num4 = out_len; int num5 = channel_index * mem_alloc_size; int num6 = mem_alloc_size - (filt_len - 1); int num7 = ((num4 < 8192) ? num4 : 8192); float[] array = new float[num7]; out_stride = 1; while (num3 != 0 && num4 != 0) { int output_ptr2 = 0; int in_len2 = ((num3 > num6) ? num6 : num3); int out_len2 = ((num4 > num7) ? num7 : num4); int num8 = 0; if (magic_samples[channel_index] != 0) { num8 = speex_resampler_magic(channel_index, array, ref output_ptr2, out_len2); out_len2 -= num8; num4 -= num8; } if (magic_samples[channel_index] == 0) { if (input != null) { for (int i = 0; i < in_len2; i++) { mem[num5 + i + filt_len - 1] = input[input_ptr + i * num]; } } else { for (int i = 0; i < in_len2; i++) { mem[num5 + i + filt_len - 1] = 0f; } } speex_resampler_process_native(channel_index, ref in_len2, array, output_ptr2, ref out_len2); } else { in_len2 = 0; out_len2 = 0; } for (int i = 0; i < out_len2 + num8; i++) { output[output_ptr + i * num2] = FLOAT2INT(array[i]); } num3 -= in_len2; num4 -= out_len2; output_ptr += (out_len2 + num8) * num2; if (input != null) { input_ptr += in_len2 * num; } } out_stride = num2; in_len -= num3; out_len -= num4; } public void ProcessInterleaved(Span input, ref int in_len, Span output, ref int out_len) { int num = out_len; int num2 = in_len; int num3 = in_stride; int num4 = out_stride; in_stride = (out_stride = nb_channels); for (int i = 0; i < nb_channels; i++) { out_len = num; in_len = num2; if (input != null) { Process(i, input, i, ref in_len, output, i, ref out_len); } else { Process(i, null, 0, ref in_len, output, i, ref out_len); } } in_stride = num3; out_stride = num4; } public void ProcessInterleaved(Span input, ref int in_len, Span output, ref int out_len) { int num = out_len; int num2 = in_len; int num3 = in_stride; int num4 = out_stride; in_stride = (out_stride = nb_channels); for (int i = 0; i < nb_channels; i++) { out_len = num; in_len = num2; if (input != null) { Process(i, input, i, ref in_len, output, i, ref out_len); } else { Process(i, null, 0, ref in_len, output, i, ref out_len); } } in_stride = num3; out_stride = num4; } public void SkipZeroes() { for (int i = 0; i < nb_channels; i++) { last_sample[i] = filt_len / 2; } } public void ResetMem() { for (int i = 0; i < nb_channels; i++) { last_sample[i] = 0; magic_samples[i] = 0; samp_frac_num[i] = 0; } for (int i = 0; i < nb_channels * (filt_len - 1); i++) { mem[i] = 0f; } } public void Dispose() { } public void SetRates(int in_rate, int out_rate) { SetRateFraction(in_rate, out_rate, in_rate, out_rate); } public void GetRates(out int in_rate, out int out_rate) { in_rate = this.in_rate; out_rate = this.out_rate; } public void SetRateFraction(int ratio_num, int ratio_den, int in_rate, int out_rate) { if (this.in_rate == in_rate && this.out_rate == out_rate && num_rate == ratio_num && den_rate == ratio_den) { return; } int num = den_rate; this.in_rate = in_rate; this.out_rate = out_rate; num_rate = ratio_num; den_rate = ratio_den; for (int i = 2; i <= Inlines.IMIN(num_rate, den_rate); i++) { while (num_rate % i == 0 && den_rate % i == 0) { num_rate /= i; den_rate /= i; } } if (num > 0) { for (int j = 0; j < nb_channels; j++) { samp_frac_num[j] = samp_frac_num[j] * den_rate / num; if (samp_frac_num[j] >= den_rate) { samp_frac_num[j] = den_rate - 1; } } } if (initialised != 0) { update_filter(); } } public void GetRateFraction(out int ratio_num, out int ratio_den) { ratio_num = num_rate; ratio_den = den_rate; } } } namespace Concentus.Common.CPlusPlus { internal static class Arrays { internal static T[][] InitTwoDimensionalArray(int x, int y) { T[][] array = new T[x][]; for (int i = 0; i < x; i++) { array[i] = new T[y]; } return array; } internal static Pointer> InitTwoDimensionalArrayPointer(int x, int y) { Pointer> pointer = Pointer.Malloc>(x); for (int i = 0; i < x; i++) { pointer[i] = Pointer.Malloc(y); } return pointer; } internal static T[][][] InitThreeDimensionalArray(int x, int y, int z) { T[][][] array = new T[x][][]; for (int i = 0; i < x; i++) { array[i] = new T[y][]; for (int j = 0; j < y; j++) { array[i][j] = new T[z]; } } return array; } internal static void MemSetByte(byte[] array, byte value) { array.AsSpan().Fill(value); } internal static void MemSetInt(int[] array, int value, int length) { array.AsSpan(0, length).Fill(value); } internal static void MemSetShort(short[] array, short value, int length) { array.AsSpan(0, length).Fill(value); } internal static void MemSetFloat(float[] array, float value, int length) { array.AsSpan(0, length).Fill(value); } internal static void MemSetSbyte(sbyte[] array, sbyte value, int length) { array.AsSpan(0, length).Fill(value); } internal static void MemSetWithOffset(T[] array, T value, int offset, int length) { array.AsSpan(offset, length).Fill(value); } internal static void MemSetWithOffset(Span array, T value, int offset, int length) { array.Slice(offset, length).Fill(value); } internal static void MemMoveByte(byte[] array, int src_idx, int dst_idx, int length) { if (src_idx != dst_idx && length != 0) { Buffer.BlockCopy(array, src_idx, array, dst_idx, length); } } internal static void MemMoveByte(Span array, int src_idx, int dst_idx, int length) { if (src_idx != dst_idx && length != 0) { array.Slice(src_idx, length).CopyTo(array.Slice(dst_idx, length)); } } internal static void MemCopy(int[] src, int src_idx, int[] dst, int dst_idx, int length) { if (length != 0) { Buffer.BlockCopy(src, src_idx * 4, dst, dst_idx * 4, length * 4); } } internal static void MemCopy(short[] src, int src_idx, short[] dst, int dst_idx, int length) { if (length != 0) { Buffer.BlockCopy(src, src_idx * 2, dst, dst_idx * 2, length * 2); } } internal static void MemCopy(sbyte[] src, int src_idx, sbyte[] dst, int dst_idx, int length) { if (length != 0) { Buffer.BlockCopy(src, src_idx, dst, dst_idx, length); } } internal static void MemMoveInt(int[] array, int src_idx, int dst_idx, int length) { if (src_idx != dst_idx && length != 0) { Buffer.BlockCopy(array, src_idx * 4, array, dst_idx * 4, length * 4); } } internal static void MemMoveShort(short[] array, int src_idx, int dst_idx, int length) { if (src_idx != dst_idx && length != 0) { Buffer.BlockCopy(array, src_idx * 2, array, dst_idx * 2, length * 2); } } } internal class BoxedValueInt { internal int Val; internal BoxedValueInt(int v = 0) { Val = v; } public override string ToString() { return Val.ToString(); } } internal class BoxedValueShort { internal short Val; internal BoxedValueShort(short v = 0) { Val = v; } public override string ToString() { return Val.ToString(); } } internal class BoxedValueSbyte { internal sbyte Val; internal BoxedValueSbyte(sbyte v = 0) { Val = v; } public override string ToString() { return Val.ToString(); } } internal class BoxedValue { internal T Val; internal BoxedValue(T v = default(T)) { Val = v; } public override string ToString() { if (Val != null) { return Val.ToString(); } return "null"; } } internal class Pointer { private const bool CHECK_UNINIT_MEM = false; private T[] _array; private int _offset; internal int Offset => _offset; internal T[] Data => _array; internal T this[int index] { get { return _array[index + _offset]; } set { _array[index + _offset] = value; } } internal T this[uint index] { get { return this[(int)index]; } set { this[(int)index] = value; } } internal Pointer(int capacity) { _array = new T[capacity]; _offset = 0; } internal Pointer(T[] buffer) { _array = buffer; _offset = 0; } internal Pointer(T[] buffer, int absoluteOffset) { _array = buffer; _offset = absoluteOffset; } internal Pointer Iterate(out T returnVal) { returnVal = _array[_offset]; return Point(1); } internal Pointer Point(int relativeOffset) { if (relativeOffset == 0) { return this; } return new Pointer(_array, _offset + relativeOffset); } internal Pointer Point(uint relativeOffset) { if (relativeOffset == 0) { return this; } return new Pointer(_array, _offset + (int)relativeOffset); } private static string invert_endianness(string hexstring) { StringBuilder stringBuilder = new StringBuilder(hexstring.Length); for (int i = 0; i < hexstring.Length / 2; i++) { stringBuilder.Append(hexstring.Substring(hexstring.Length - (i + 1) * 2, 2)); } return stringBuilder.ToString(); } private static void PrintMemCopy(E[] source, int sourceOffset, int length) { if (typeof(E) == typeof(int) || typeof(E) == typeof(uint)) { string text = string.Empty; for (int i = 0; i < length; i++) { text += invert_endianness($"{source[i + sourceOffset]:x8}"); } } else if (typeof(E) == typeof(short) || typeof(E) == typeof(ushort)) { string text2 = string.Empty; for (int j = 0; j < length; j++) { text2 += invert_endianness($"{source[j + sourceOffset]:x4}"); } } else if (typeof(E) == typeof(byte) || typeof(E) == typeof(sbyte)) { string text3 = string.Empty; for (int k = 0; k < length; k++) { text3 += invert_endianness($"{source[k + sourceOffset]:x2}"); } } } internal void MemCopyTo(Pointer destination, int length) { if (destination != null) { Array.Copy(_array, _offset, destination._array, destination.Offset, length); return; } for (int i = 0; i < length; i++) { destination[i] = _array[i + _offset]; } } internal void MemCopyTo(T[] destination, int offset, int length) { Array.Copy(_array, _offset, destination, offset, length); } internal void MemCopyFrom(T[] source, int sourceOffset, int length) { Array.Copy(source, sourceOffset, _array, _offset, length); } internal void MemSet(T value, int length) { MemSet(value, (uint)length); } internal void MemSet(T value, uint length) { for (int i = _offset; i < _offset + length; i++) { _array[i] = value; } } internal void MemMoveTo(Pointer other, int length) { if (_array == other._array) { MemMove(other.Offset - Offset, length); } else { MemCopyTo(other, length); } } internal void MemMove(int move_dist, int length) { _array.AsSpan(_offset, length).CopyTo(_array.AsSpan(_offset + move_dist, length)); } public override bool Equals(object obj) { if (obj == null || GetType() != obj.GetType()) { return false; } Pointer pointer = (Pointer)obj; if (pointer._offset == _offset) { return pointer._array == _array; } return false; } public override int GetHashCode() { return _array.GetHashCode() + _offset.GetHashCode(); } } internal static class Pointer { internal static Pointer Malloc(int capacity) { return new Pointer(capacity); } internal static Pointer GetPointer(this E[] memory, int offset = 0) { if (memory == null) { return null; } return new Pointer(memory, offset); } } } namespace Concentus.Celt { internal static class Bands { internal class band_ctx { internal int encode; internal CeltMode m; internal int i; internal int intensity; internal int spread; internal int tf_change; internal EntropyCoder ec; internal int remaining_bits; internal int[][] bandE; internal uint seed; } internal class split_ctx { internal int inv; internal int imid; internal int iside; internal int delta; internal int itheta; internal int qalloc; } private static readonly byte[] bit_interleave_table = new byte[16] { 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3 }; private static readonly byte[] bit_deinterleave_table = new byte[16] { 0, 3, 12, 15, 48, 51, 60, 63, 192, 195, 204, 207, 240, 243, 252, 255 }; internal static int hysteresis_decision(int val, int[] thresholds, int[] hysteresis, int N, int prev) { int i; for (i = 0; i < N && val >= thresholds[i]; i++) { } if (i > prev && val < thresholds[prev] + hysteresis[prev]) { i = prev; } if (i < prev && val > thresholds[prev - 1] - hysteresis[prev - 1]) { i = prev; } return i; } internal static uint celt_lcg_rand(uint seed) { return 1664525 * seed + 1013904223; } internal static int bitexact_cos(int x) { int num = 4096 + x * x >> 13; num = 32767 - num + Inlines.FRAC_MUL16(num, -7651 + Inlines.FRAC_MUL16(num, 8277 + Inlines.FRAC_MUL16(-626, num))); return 1 + num; } internal static int bitexact_log2tan(int isin, int icos) { int num = Inlines.EC_ILOG((uint)icos); int num2 = Inlines.EC_ILOG((uint)isin); icos <<= 15 - num; isin <<= 15 - num2; return (num2 - num) * 2048 + Inlines.FRAC_MUL16(isin, Inlines.FRAC_MUL16(isin, -2597) + 7932) - Inlines.FRAC_MUL16(icos, Inlines.FRAC_MUL16(icos, -2597) + 7932); } internal static void compute_band_energies(CeltMode m, int[][] X, int[][] bandE, int end, int C, int LM) { short[] eBands = m.eBands; _ = m.shortMdctSize; int num = 0; do { for (int i = 0; i < end; i++) { int num2 = 0; int num3 = 0; num2 = Inlines.celt_maxabs32(X[num], eBands[i] << LM, eBands[i + 1] - eBands[i] << LM); if (num2 > 0) { int num4 = Inlines.celt_ilog2(num2) - 14 + ((m.logN[i] >> 3) + LM + 1 >> 1); int num5 = eBands[i] << LM; if (num4 > 0) { do { num3 = Inlines.MAC16_16(num3, Inlines.EXTRACT16(Inlines.SHR32(X[num][num5], num4)), Inlines.EXTRACT16(Inlines.SHR32(X[num][num5], num4))); } while (++num5 < eBands[i + 1] << LM); } else { do { num3 = Inlines.MAC16_16(num3, Inlines.EXTRACT16(Inlines.SHL32(X[num][num5], -num4)), Inlines.EXTRACT16(Inlines.SHL32(X[num][num5], -num4))); } while (++num5 < eBands[i + 1] << LM); } bandE[num][i] = 1 + Inlines.VSHR32(Inlines.celt_sqrt(num3), -num4); } else { bandE[num][i] = 1; } } } while (++num < C); } internal static void normalise_bands(CeltMode m, int[][] freq, int[][] X, int[][] bandE, int end, int C, int M) { short[] eBands = m.eBands; int num = 0; do { int num2 = 0; do { int num3 = Inlines.celt_zlog2(bandE[num][num2]) - 13; int b = Inlines.EXTRACT16(Inlines.celt_rcp(Inlines.SHL32(Inlines.VSHR32(bandE[num][num2], num3), 3))); int num4 = M * eBands[num2]; do { X[num][num4] = Inlines.MULT16_16_Q15(Inlines.VSHR32(freq[num][num4], num3 - 1), b); } while (++num4 < M * eBands[num2 + 1]); } while (++num2 < end); } while (++num < C); } internal static void denormalise_bands(CeltMode m, int[] X, Span freq, int freq_ptr, Span bandLogE, int bandLogE_ptr, int start, int end, int M, int downsample, int silence) { short[] eBands = m.eBands; int num = M * m.shortMdctSize; int num2 = M * eBands[end]; if (downsample != 1) { num2 = Inlines.IMIN(num2, num / downsample); } if (silence != 0) { num2 = 0; start = (end = 0); } int index = freq_ptr; int num3 = M * eBands[start]; for (int i = 0; i < M * eBands[start]; i++) { freq[index++] = 0; } for (int i = start; i < end; i++) { int num4 = M * eBands[i]; int num5 = M * eBands[i + 1]; int num6 = Inlines.ADD16(bandLogE[bandLogE_ptr + i], Inlines.SHL16(Tables.eMeans[i], 6)); int num7 = 16 - (num6 >> 10); int b; if (num7 > 31) { num7 = 0; b = 0; } else { b = Inlines.celt_exp2_frac(num6 & 0x3FF); } if (num7 < 0) { if (num7 < -2) { b = 32767; num7 = -2; } do { freq[index] = Inlines.SHR32(Inlines.MULT16_16(X[num3], b), -num7); } while (++num4 < num5); } else { do { freq[index++] = Inlines.SHR32(Inlines.MULT16_16(X[num3++], b), num7); } while (++num4 < num5); } } Arrays.MemSetWithOffset(freq, 0, freq_ptr + num2, num - num2); } internal static void anti_collapse(CeltMode m, int[][] X_, byte[] collapse_masks, int LM, int C, int size, int start, int end, int[] logE, int[] prev1logE, int[] prev2logE, int[] pulses, uint seed) { for (int i = start; i < end; i++) { int num = m.eBands[i + 1] - m.eBands[i]; int a = Inlines.celt_udiv(1 + pulses[i], m.eBands[i + 1] - m.eBands[i]) >> LM; int b = Inlines.SHR32(Inlines.celt_exp2(-Inlines.SHL16(a, 7)), 1); int a2 = Inlines.MULT16_32_Q15((short)16384, Inlines.MIN32(32767, b)); int num2 = num << LM; int num3 = Inlines.celt_ilog2(num2) >> 1; int a3 = Inlines.celt_rsqrt_norm(Inlines.SHL32(num2, 7 - num3 << 1)); int num4 = 0; do { int num5 = 0; int a4 = prev1logE[num4 * m.nbEBands + i]; int num6 = prev2logE[num4 * m.nbEBands + i]; if (C == 1) { a4 = Inlines.MAX16(a4, prev1logE[m.nbEBands + i]); num6 = Inlines.MAX16(num6, prev2logE[m.nbEBands + i]); } int b2 = Inlines.EXTEND32(logE[num4 * m.nbEBands + i]) - Inlines.EXTEND32(Inlines.MIN16(a4, num6)); b2 = Inlines.MAX32(0, b2); int b4; if (b2 < 16384) { int b3 = Inlines.SHR32(Inlines.celt_exp2((short)(-Inlines.EXTRACT16(b2))), 1); b4 = 2 * Inlines.MIN16(16383, b3); } else { b4 = 0; } if (LM == 3) { b4 = Inlines.MULT16_16_Q14(23170, Inlines.MIN32(23169, b4)); } b4 = Inlines.SHR16(Inlines.MIN16(a2, b4), 1); b4 = Inlines.SHR32(Inlines.MULT16_16_Q15(a3, b4), num3); int num7 = m.eBands[i] << LM; for (int j = 0; j < 1 << LM; j++) { if ((collapse_masks[i * C + num4] & (1 << j)) == 0) { int num8 = num7 + j; for (int k = 0; k < num; k++) { seed = celt_lcg_rand(seed); X_[num4][num8 + (k << LM)] = (((seed & 0x8000u) != 0) ? b4 : (-b4)); } num5 = 1; } } if (num5 != 0) { VQ.renormalise_vector(X_[num4].AsSpan().Slice(num7), num << LM, 32767); } } while (++num4 < C); } } internal static void intensity_stereo(CeltMode m, Span X, int X_ptr, Span Y, int Y_ptr, int[][] bandE, int bandID, int N) { int shift = Inlines.celt_zlog2(Inlines.MAX32(bandE[0][bandID], bandE[1][bandID])) - 13; int num = Inlines.VSHR32(bandE[0][bandID], shift); int num2 = Inlines.VSHR32(bandE[1][bandID], shift); int b = 1 + Inlines.celt_sqrt(1 + Inlines.MULT16_16(num, num) + Inlines.MULT16_16(num2, num2)); int a = Inlines.DIV32_16(Inlines.SHL32(num, 14), b); int a2 = Inlines.DIV32_16(Inlines.SHL32(num2, 14), b); for (int i = 0; i < N; i++) { int b2 = X[X_ptr + i]; int b3 = Y[Y_ptr + i]; X[X_ptr + i] = Inlines.EXTRACT16(Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(a, b2), a2, b3), 14)); } } private static void stereo_split(Span X, int X_ptr, Span Y, int Y_ptr, int N) { for (int i = 0; i < N; i++) { int num = Inlines.MULT16_16(23170, X[X_ptr + i]); int num2 = Inlines.MULT16_16(23170, Y[Y_ptr + i]); X[X_ptr + i] = Inlines.EXTRACT16(Inlines.SHR32(Inlines.ADD32(num, num2), 15)); Y[Y_ptr + i] = Inlines.EXTRACT16(Inlines.SHR32(Inlines.SUB32(num2, num), 15)); } } private static void stereo_merge(Span X, Span Y, int mid, int N) { Kernels.dual_inner_prod(Y, X, Y, N, out var xy, out var xy2); xy = Inlines.MULT16_32_Q15(mid, xy); int num = Inlines.SHR16(mid, 1); int num2 = Inlines.MULT16_16(num, num) + xy2 - 2 * xy; int num3 = Inlines.MULT16_16(num, num) + xy2 + 2 * xy; if (num3 < 161061 || num2 < 161061) { X.Slice(0, N).CopyTo(Y); return; } int num4 = Inlines.celt_ilog2(num2) >> 1; int num5 = Inlines.celt_ilog2(num3) >> 1; int a = Inlines.celt_rsqrt_norm(Inlines.VSHR32(num2, num4 - 7 << 1)); int a2 = Inlines.celt_rsqrt_norm(Inlines.VSHR32(num3, num5 - 7 << 1)); if (num4 < 7) { num4 = 7; } if (num5 < 7) { num5 = 7; } for (int i = 0; i < N; i++) { int a3 = Inlines.MULT16_16_P15(mid, X[i]); int b = Y[i]; X[i] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MULT16_16(a, Inlines.SUB16(a3, b)), num4 + 1)); Y[i] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MULT16_16(a2, Inlines.ADD16(a3, b)), num5 + 1)); } } internal static int spreading_decision(CeltMode m, int[][] X, ref int average, int last_decision, ref int hf_average, ref int tapset_decision, int update_hf, int end, int C, int M) { int num = 0; int num2 = 0; short[] eBands = m.eBands; int num3 = 0; if (M * (eBands[end] - eBands[end - 1]) <= 8) { return 0; } int num4 = 0; do { for (int i = 0; i < end; i++) { int num5 = 0; int[] array = new int[3]; int[] array2 = X[num4]; int num6 = M * eBands[i]; int num7 = M * (eBands[i + 1] - eBands[i]); if (num7 <= 8) { continue; } for (int j = num6; j < num7 + num6; j++) { int num8 = Inlines.MULT16_16(Inlines.MULT16_16_Q15(array2[j], array2[j]), num7); if (num8 < 2048) { array[0]++; } if (num8 < 512) { array[1]++; } if (num8 < 128) { array[2]++; } } if (i > m.nbEBands - 4) { num3 += Inlines.celt_udiv(32 * (array[1] + array[0]), num7); } num5 = ((2 * array[2] >= num7) ? 1 : 0) + ((2 * array[1] >= num7) ? 1 : 0) + ((2 * array[0] >= num7) ? 1 : 0); num += num5 * 256; num2++; } } while (++num4 < C); if (update_hf != 0) { if (num3 != 0) { num3 = Inlines.celt_udiv(num3, C * (4 - m.nbEBands + end)); } hf_average = hf_average + num3 >> 1; num3 = hf_average; if (tapset_decision == 2) { num3 += 4; } else if (tapset_decision == 0) { num3 -= 4; } if (num3 > 22) { tapset_decision = 2; } else if (num3 > 18) { tapset_decision = 1; } else { tapset_decision = 0; } } num = Inlines.celt_udiv(num, num2); num = 3 * (average = num + average >> 1) + ((3 - last_decision << 7) + 64) + 2 >> 2; if (num < 80) { return 3; } if (num < 256) { return 2; } if (num < 384) { return 1; } return 0; } internal static void deinterleave_hadamard(Span X, int X_ptr, int N0, int stride, int hadamard) { int num = N0 * stride; int[] array = new int[num]; if (hadamard != 0) { int num2 = stride - 2; for (int i = 0; i < stride; i++) { for (int j = 0; j < N0; j++) { array[Tables.ordery_table[num2 + i] * N0 + j] = X[j * stride + i + X_ptr]; } } } else { for (int i = 0; i < stride; i++) { for (int j = 0; j < N0; j++) { array[i * N0 + j] = X[j * stride + i + X_ptr]; } } } array.AsSpan(0, num).CopyTo(X.Slice(X_ptr)); } internal static void interleave_hadamard(Span X, int X_ptr, int N0, int stride, int hadamard) { int num = N0 * stride; int[] array = new int[num]; if (hadamard != 0) { int num2 = stride - 2; for (int i = 0; i < stride; i++) { for (int j = 0; j < N0; j++) { array[j * stride + i] = X[Tables.ordery_table[num2 + i] * N0 + j + X_ptr]; } } } else { for (int i = 0; i < stride; i++) { for (int j = 0; j < N0; j++) { array[j * stride + i] = X[i * N0 + j + X_ptr]; } } } array.AsSpan(0, num).CopyTo(X.Slice(X_ptr)); } internal static void haar1(Span X, int X_ptr, int N0, int stride) { N0 >>= 1; for (int i = 0; i < stride; i++) { for (int j = 0; j < N0; j++) { int num = X_ptr + i + stride * 2 * j; int a = Inlines.MULT16_16(23170, X[num]); int b = Inlines.MULT16_16(23170, X[num + stride]); X[num] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.ADD32(a, b), 15)); X[num + stride] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.SUB32(a, b), 15)); } } } internal static void haar1ZeroOffset(int[] X, int N0, int stride) { N0 >>= 1; for (int i = 0; i < stride; i++) { for (int j = 0; j < N0; j++) { int num = i + stride * 2 * j; int a = Inlines.MULT16_16(23170, X[num]); int b = Inlines.MULT16_16(23170, X[num + stride]); X[num] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.ADD32(a, b), 15)); X[num + stride] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.SUB32(a, b), 15)); } } } internal static int compute_qn(int N, int b, int offset, int pulse_cap, int stereo) { short[] array = new short[8] { 16384, 17866, 19483, 21247, 23170, 25267, 27554, 30048 }; int num = 2 * N - 1; if (stereo != 0 && N == 2) { num--; } int b2 = Inlines.celt_sudiv(b + num * offset, num); b2 = Inlines.IMIN(b - pulse_cap - 32, b2); b2 = Inlines.IMIN(64, b2); if (b2 < 4) { return 1; } int num2 = array[b2 & 7] >> 14 - (b2 >> 3); return num2 + 1 >> 1 << 1; } internal static void compute_theta_decode(band_ctx ctx, split_ctx sctx, ReadOnlySpan encodedData, Span X, int X_ptr, Span Y, int Y_ptr, int N, ref int b, int B, int B0, int LM, int stereo, ref int fill) { int num = 0; int inv = 0; CeltMode m = ctx.m; int i = ctx.i; int intensity = ctx.intensity; EntropyCoder ec = ctx.ec; _ = ctx.bandE; int num2 = m.logN[i] + LM * 8; int offset = (num2 >> 1) - ((stereo != 0 && N == 2) ? 16 : 4); int num3 = compute_qn(N, b, offset, num2, stereo); if (stereo != 0 && i >= intensity) { num3 = 1; } int num4 = (int)ec.tell_frac(); if (num3 != 1) { if (stereo != 0 && N > 2) { int num5 = 3; int num6 = num; int num7 = num3 / 2; uint ft = (uint)(num5 * (num7 + 1) + num7); int num8 = (int)ec.decode(ft); num6 = ((num8 >= (num7 + 1) * num5) ? (num7 + 1 + (num8 - (num7 + 1) * num5)) : (num8 / num5)); ec.dec_update(encodedData, (uint)((num6 <= num7) ? (num5 * num6) : (num6 - 1 - num7 + (num7 + 1) * num5)), (uint)((num6 <= num7) ? (num5 * (num6 + 1)) : (num6 - num7 + (num7 + 1) * num5)), ft); num = num6; } else if (B0 > 1 || stereo != 0) { num = (int)ec.dec_uint(encodedData, (uint)(num3 + 1)); } else { int num9 = 1; int num10 = ((num3 >> 1) + 1) * ((num3 >> 1) + 1); int num11 = 0; int num12 = (int)ec.decode((uint)num10); if (num12 < (num3 >> 1) * ((num3 >> 1) + 1) >> 1) { num = (int)(Inlines.isqrt32((uint)(8 * num12 + 1)) - 1) >> 1; num9 = num + 1; num11 = num * (num + 1) >> 1; } else { num = (int)(2 * (num3 + 1) - Inlines.isqrt32((uint)(8 * (num10 - num12 - 1) + 1))) >> 1; num9 = num3 + 1 - num; num11 = num10 - ((num3 + 1 - num) * (num3 + 2 - num) >> 1); } ec.dec_update(encodedData, (uint)num11, (uint)(num11 + num9), (uint)num10); } num = Inlines.celt_udiv(num * 16384, num3); } else if (stereo != 0) { inv = ((b > 16 && ctx.remaining_bits > 16) ? ec.dec_bit_logp(encodedData, 2u) : 0); num = 0; } int num13 = (int)ec.tell_frac() - num4; b -= num13; int num14; int num15; int delta; switch (num) { case 0: num14 = 32767; num15 = 0; fill &= (1 << B) - 1; delta = -16384; break; case 16384: num14 = 0; num15 = 32767; fill &= (1 << B) - 1 << B; delta = 16384; break; default: num14 = bitexact_cos((short)num); num15 = bitexact_cos((short)(16384 - num)); delta = Inlines.FRAC_MUL16(N - 1 << 7, bitexact_log2tan(num15, num14)); break; } sctx.inv = inv; sctx.imid = num14; sctx.iside = num15; sctx.delta = delta; sctx.itheta = num; sctx.qalloc = num13; } internal static void compute_theta_encode(band_ctx ctx, split_ctx sctx, Span encodedData, Span X, int X_ptr, Span Y, int Y_ptr, int N, ref int b, int B, int B0, int LM, int stereo, ref int fill) { int num = 0; int num2 = 0; CeltMode m = ctx.m; int i = ctx.i; int intensity = ctx.intensity; EntropyCoder ec = ctx.ec; int[][] bandE = ctx.bandE; int num3 = m.logN[i] + LM * 8; int offset = (num3 >> 1) - ((stereo != 0 && N == 2) ? 16 : 4); int num4 = compute_qn(N, b, offset, num3, stereo); if (stereo != 0 && i >= intensity) { num4 = 1; } num = VQ.stereo_itheta(X.Slice(X_ptr), Y.Slice(Y_ptr), stereo, N); int num5 = (int)ec.tell_frac(); if (num4 != 1) { num = num * num4 + 8192 >> 14; if (stereo != 0 && N > 2) { int num6 = 3; int num7 = num; int num8 = num4 / 2; uint ft = (uint)(num6 * (num8 + 1) + num8); ec.encode(encodedData, (uint)((num7 <= num8) ? (num6 * num7) : (num7 - 1 - num8 + (num8 + 1) * num6)), (uint)((num7 <= num8) ? (num6 * (num7 + 1)) : (num7 - num8 + (num8 + 1) * num6)), ft); } else if (B0 > 1 || stereo != 0) { ec.enc_uint(encodedData, (uint)num, (uint)(num4 + 1)); } else { int num9 = 1; int num10 = ((num4 >> 1) + 1) * ((num4 >> 1) + 1); num9 = ((num <= num4 >> 1) ? (num + 1) : (num4 + 1 - num)); int num11 = ((num <= num4 >> 1) ? (num * (num + 1) >> 1) : (num10 - ((num4 + 1 - num) * (num4 + 2 - num) >> 1))); ec.encode(encodedData, (uint)num11, (uint)(num11 + num9), (uint)num10); } num = Inlines.celt_udiv(num * 16384, num4); if (stereo != 0) { if (num == 0) { intensity_stereo(m, X, X_ptr, Y, Y_ptr, bandE, i, N); } else { stereo_split(X, X_ptr, Y, Y_ptr, N); } } } else if (stereo != 0) { num2 = ((num > 8192) ? 1 : 0); if (num2 != 0) { for (int j = 0; j < N; j++) { Y[Y_ptr + j] = -Y[Y_ptr + j]; } } intensity_stereo(m, X, X_ptr, Y, Y_ptr, bandE, i, N); if (b > 16 && ctx.remaining_bits > 16) { ec.enc_bit_logp(encodedData, num2, 2u); } else { num2 = 0; } num = 0; } int num12 = (int)ec.tell_frac() - num5; b -= num12; int num13; int num14; int delta; switch (num) { case 0: num13 = 32767; num14 = 0; fill &= (1 << B) - 1; delta = -16384; break; case 16384: num13 = 0; num14 = 32767; fill &= (1 << B) - 1 << B; delta = 16384; break; default: num13 = bitexact_cos((short)num); num14 = bitexact_cos((short)(16384 - num)); delta = Inlines.FRAC_MUL16(N - 1 << 7, bitexact_log2tan(num14, num13)); break; } sctx.inv = num2; sctx.imid = num13; sctx.iside = num14; sctx.delta = delta; sctx.itheta = num; sctx.qalloc = num12; } internal static uint quant_band_n1_encode(band_ctx ctx, Span encodedData, Span X, int X_ptr, Span Y, int Y_ptr, int b, Span lowband_out, int lowband_out_ptr) { int num = 0; Span span = X; int index = X_ptr; EntropyCoder ec = ctx.ec; int num2 = ((!Y.IsEmpty) ? 1 : 0); int num3 = 0; do { int num4 = 0; if (ctx.remaining_bits >= 8) { num4 = ((span[index] < 0) ? 1 : 0); ec.enc_bits(encodedData, (uint)num4, 1u); ctx.remaining_bits -= 8; b -= 8; } if (num != 0) { span[index] = ((num4 != 0) ? (-16384) : 16384); } span = Y; index = Y_ptr; } while (++num3 < 1 + num2); if (!lowband_out.IsEmpty) { lowband_out[lowband_out_ptr] = Inlines.SHR16(X[X_ptr], 4); } return 1u; } internal static uint quant_band_n1_decode(band_ctx ctx, ReadOnlySpan encodedData, Span X, int X_ptr, Span Y, int Y_ptr, int b, Span lowband_out, int lowband_out_ptr) { int num = 1; Span span = X; int index = X_ptr; EntropyCoder ec = ctx.ec; int num2 = ((!Y.IsEmpty) ? 1 : 0); int num3 = 0; do { int num4 = 0; if (ctx.remaining_bits >= 8) { num4 = (int)ec.dec_bits(encodedData, 1u); ctx.remaining_bits -= 8; b -= 8; } if (num != 0) { span[index] = ((num4 != 0) ? (-16384) : 16384); } span = Y; index = Y_ptr; } while (++num3 < 1 + num2); if (!lowband_out.IsEmpty) { lowband_out[lowband_out_ptr] = Inlines.SHR16(X[X_ptr], 4); } return 1u; } internal static uint quant_partition_encode(band_ctx ctx, Span encodedData, Span X, int X_ptr, int N, int b, int B, Span lowband, int lowband_ptr, int LM, int gain, int fill) { int num = 0; int num2 = B; int num3 = 0; int num4 = 0; uint result = 0u; int num5 = 0; int num6 = 0; CeltMode m = ctx.m; int i = ctx.i; int spread = ctx.spread; EntropyCoder ec = ctx.ec; byte[] bits = m.cache.bits; int num7 = m.cache.index[(LM + 1) * m.nbEBands + i]; if (LM != -1 && b > bits[num7 + bits[num7]] + 12 && N > 2) { split_ctx split_ctx = new split_ctx(); int lowband_ptr2 = 0; N >>= 1; num6 = X_ptr + N; LM--; if (B == 1) { fill = (fill & 1) | (fill << 1); } B = B + 1 >> 1; compute_theta_encode(ctx, split_ctx, encodedData, X, X_ptr, X, num6, N, ref b, B, num2, LM, 0, ref fill); num = split_ctx.imid; int iside = split_ctx.iside; int num8 = split_ctx.delta; int itheta = split_ctx.itheta; int qalloc = split_ctx.qalloc; num3 = num; num4 = iside; if (num2 > 1 && ((uint)itheta & 0x3FFFu) != 0) { num8 = ((itheta <= 8192) ? Inlines.IMIN(0, num8 + (N << 3 >> 5 - LM)) : (num8 - (num8 >> 4 - LM))); } int num9 = Inlines.IMAX(0, Inlines.IMIN(b, (b - num8) / 2)); int num10 = b - num9; ctx.remaining_bits -= qalloc; if (!lowband.IsEmpty) { lowband_ptr2 = lowband_ptr + N; } int remaining_bits = ctx.remaining_bits; if (num9 >= num10) { result = quant_partition_encode(ctx, encodedData, X, X_ptr, N, num9, B, lowband, lowband_ptr, LM, Inlines.MULT16_16_P15(gain, num3), fill); remaining_bits = num9 - (remaining_bits - ctx.remaining_bits); if (remaining_bits > 24 && itheta != 0) { num10 += remaining_bits - 24; } result |= quant_partition_encode(ctx, encodedData, X, num6, N, num10, B, lowband, lowband_ptr2, LM, Inlines.MULT16_16_P15(gain, num4), fill >> B) << (num2 >> 1); } else { result = quant_partition_encode(ctx, encodedData, X, num6, N, num10, B, lowband, lowband_ptr2, LM, Inlines.MULT16_16_P15(gain, num4), fill >> B) << (num2 >> 1); remaining_bits = num10 - (remaining_bits - ctx.remaining_bits); if (remaining_bits > 24 && itheta != 16384) { num9 += remaining_bits - 24; } result |= quant_partition_encode(ctx, encodedData, X, X_ptr, N, num9, B, lowband, lowband_ptr, LM, Inlines.MULT16_16_P15(gain, num3), fill); } } else { int num11 = Rate.bits2pulses(m, i, LM, b); int num12 = Rate.pulses2bits(m, i, LM, num11); ctx.remaining_bits -= num12; while (ctx.remaining_bits < 0 && num11 > 0) { ctx.remaining_bits += num12; num11--; num12 = Rate.pulses2bits(m, i, LM, num11); ctx.remaining_bits -= num12; } if (num11 != 0) { int k = Rate.get_pulses(num11); result = VQ.alg_quant(X, X_ptr, N, k, spread, B, ec, encodedData); } else if (num5 != 0) { uint num13 = (uint)((int)(1L << B) - 1); fill &= (int)num13; if (fill == 0) { Arrays.MemSetWithOffset(X, 0, X_ptr, N); } else { if (lowband.IsEmpty) { for (int j = 0; j < N; j++) { ctx.seed = celt_lcg_rand(ctx.seed); X[X_ptr + j] = (int)ctx.seed >> 20; } result = num13; } else { for (int j = 0; j < N; j++) { ctx.seed = celt_lcg_rand(ctx.seed); int num14 = 4; num14 = (((ctx.seed & 0x8000u) != 0) ? num14 : (-num14)); X[X_ptr + j] = lowband[lowband_ptr + j] + num14; } result = (uint)fill; } VQ.renormalise_vector(X.Slice(X_ptr), N, gain); } } } return result; } internal static uint quant_partition_decode(band_ctx ctx, ReadOnlySpan encodedData, Span X, int X_ptr, int N, int b, int B, Span lowband, int lowband_ptr, int LM, int gain, int fill) { int num = 0; int num2 = B; int num3 = 0; int num4 = 0; uint result = 0u; int num5 = 1; int num6 = 0; CeltMode m = ctx.m; int i = ctx.i; int spread = ctx.spread; EntropyCoder ec = ctx.ec; byte[] bits = m.cache.bits; int num7 = m.cache.index[(LM + 1) * m.nbEBands + i]; if (LM != -1 && b > bits[num7 + bits[num7]] + 12 && N > 2) { split_ctx split_ctx = new split_ctx(); int lowband_ptr2 = 0; N >>= 1; num6 = X_ptr + N; LM--; if (B == 1) { fill = (fill & 1) | (fill << 1); } B = B + 1 >> 1; compute_theta_decode(ctx, split_ctx, encodedData, X, X_ptr, X, num6, N, ref b, B, num2, LM, 0, ref fill); num = split_ctx.imid; int iside = split_ctx.iside; int num8 = split_ctx.delta; int itheta = split_ctx.itheta; int qalloc = split_ctx.qalloc; num3 = num; num4 = iside; if (num2 > 1 && ((uint)itheta & 0x3FFFu) != 0) { num8 = ((itheta <= 8192) ? Inlines.IMIN(0, num8 + (N << 3 >> 5 - LM)) : (num8 - (num8 >> 4 - LM))); } int num9 = Inlines.IMAX(0, Inlines.IMIN(b, (b - num8) / 2)); int num10 = b - num9; ctx.remaining_bits -= qalloc; if (!lowband.IsEmpty) { lowband_ptr2 = lowband_ptr + N; } int remaining_bits = ctx.remaining_bits; if (num9 >= num10) { result = quant_partition_decode(ctx, encodedData, X, X_ptr, N, num9, B, lowband, lowband_ptr, LM, Inlines.MULT16_16_P15(gain, num3), fill); remaining_bits = num9 - (remaining_bits - ctx.remaining_bits); if (remaining_bits > 24 && itheta != 0) { num10 += remaining_bits - 24; } result |= quant_partition_decode(ctx, encodedData, X, num6, N, num10, B, lowband, lowband_ptr2, LM, Inlines.MULT16_16_P15(gain, num4), fill >> B) << (num2 >> 1); } else { result = quant_partition_decode(ctx, encodedData, X, num6, N, num10, B, lowband, lowband_ptr2, LM, Inlines.MULT16_16_P15(gain, num4), fill >> B) << (num2 >> 1); remaining_bits = num10 - (remaining_bits - ctx.remaining_bits); if (remaining_bits > 24 && itheta != 16384) { num9 += remaining_bits - 24; } result |= quant_partition_decode(ctx, encodedData, X, X_ptr, N, num9, B, lowband, lowband_ptr, LM, Inlines.MULT16_16_P15(gain, num3), fill); } } else { int num11 = Rate.bits2pulses(m, i, LM, b); int num12 = Rate.pulses2bits(m, i, LM, num11); ctx.remaining_bits -= num12; while (ctx.remaining_bits < 0 && num11 > 0) { ctx.remaining_bits += num12; num11--; num12 = Rate.pulses2bits(m, i, LM, num11); ctx.remaining_bits -= num12; } if (num11 != 0) { int k = Rate.get_pulses(num11); result = VQ.alg_unquant(X, X_ptr, N, k, spread, B, ec, encodedData, gain); } else if (num5 != 0) { uint num13 = (uint)((int)(1L << B) - 1); fill &= (int)num13; if (fill == 0) { Arrays.MemSetWithOffset(X, 0, X_ptr, N); } else { if (lowband.IsEmpty) { for (int j = 0; j < N; j++) { ctx.seed = celt_lcg_rand(ctx.seed); X[X_ptr + j] = (int)ctx.seed >> 20; } result = num13; } else { for (int j = 0; j < N; j++) { ctx.seed = celt_lcg_rand(ctx.seed); int num14 = 4; num14 = (((ctx.seed & 0x8000u) != 0) ? num14 : (-num14)); X[X_ptr + j] = lowband[lowband_ptr + j] + num14; } result = (uint)fill; } VQ.renormalise_vector(X.Slice(X_ptr), N, gain); } } } return result; } internal static uint quant_band_encode(band_ctx ctx, Span encodedData, Span X, int X_ptr, int N, int b, int B, Span lowband, int lowband_ptr, int LM, Span lowband_out, int lowband_out_ptr, int gain, Span lowband_scratch, int lowband_scratch_ptr, int fill) { int n = N; int num = B; int num2 = 0; int num3 = 0; uint num4 = 0u; int num5 = 1; int num6 = ctx.tf_change; int hadamard = ((num == 1) ? 1 : 0); n = Inlines.celt_udiv(n, B); if (N == 1) { return quant_band_n1_encode(ctx, encodedData, X, X_ptr, null, 0, b, lowband_out, lowband_out_ptr); } if (num6 > 0) { num3 = num6; } if (!lowband_scratch.IsEmpty && !lowband.IsEmpty && (num3 != 0 || ((n & 1) == 0 && num6 < 0) || num > 1)) { lowband.Slice(lowband_ptr, N).CopyTo(lowband_scratch.Slice(lowband_scratch_ptr, N)); lowband = lowband_scratch; lowband_ptr = lowband_scratch_ptr; } for (int i = 0; i < num3; i++) { haar1(X, X_ptr, N >> i, 1 << i); if (!lowband.IsEmpty) { haar1(lowband, lowband_ptr, N >> i, 1 << i); } fill = bit_interleave_table[fill & 0xF] | (bit_interleave_table[fill >> 4] << 2); } B >>= num3; n <<= num3; while ((n & 1) == 0 && num6 < 0) { haar1(X, X_ptr, n, B); if (!lowband.IsEmpty) { haar1(lowband, lowband_ptr, n, B); } fill |= fill << B; B <<= 1; n >>= 1; num2++; num6++; } num = B; int num7 = n; if (num > 1) { deinterleave_hadamard(X, X_ptr, n >> num3, num << num3, hadamard); if (!lowband.IsEmpty) { deinterleave_hadamard(lowband, lowband_ptr, n >> num3, num << num3, hadamard); } } num4 = quant_partition_encode(ctx, encodedData, X, X_ptr, N, b, B, lowband, lowband_ptr, LM, gain, fill); if (num5 != 0) { if (num > 1) { interleave_hadamard(X, X_ptr, n >> num3, num << num3, hadamard); } n = num7; B = num; for (int i = 0; i < num2; i++) { B >>= 1; n <<= 1; num4 |= num4 >> B; haar1(X, X_ptr, n, B); } for (int i = 0; i < num3; i++) { num4 = bit_deinterleave_table[num4]; haar1(X, X_ptr, N >> i, 1 << i); } B <<= num3; if (!lowband_out.IsEmpty) { int a = Inlines.celt_sqrt(Inlines.SHL32(N, 22)); for (int j = 0; j < N; j++) { lowband_out[lowband_out_ptr + j] = Inlines.MULT16_16_Q15(a, X[X_ptr + j]); } } num4 &= (uint)((1 << B) - 1); } return num4; } internal static uint quant_band_decode(band_ctx ctx, ReadOnlySpan encodedData, Span X, int X_ptr, int N, int b, int B, Span lowband, int lowband_ptr, int LM, Span lowband_out, int lowband_out_ptr, int gain, Span lowband_scratch, int lowband_scratch_ptr, int fill) { int n = N; int num = B; int num2 = 0; int num3 = 0; uint num4 = 0u; int num5 = 1; int num6 = ctx.tf_change; int hadamard = ((num == 1) ? 1 : 0); n = Inlines.celt_udiv(n, B); if (N == 1) { return quant_band_n1_decode(ctx, encodedData, X, X_ptr, null, 0, b, lowband_out, lowband_out_ptr); } if (num6 > 0) { num3 = num6; } if (!lowband_scratch.IsEmpty && !lowband.IsEmpty && (num3 != 0 || ((n & 1) == 0 && num6 < 0) || num > 1)) { lowband.Slice(lowband_ptr, N).CopyTo(lowband_scratch.Slice(lowband_scratch_ptr, N)); lowband = lowband_scratch; lowband_ptr = lowband_scratch_ptr; } for (int i = 0; i < num3; i++) { if (!lowband.IsEmpty) { haar1(lowband, lowband_ptr, N >> i, 1 << i); } fill = bit_interleave_table[fill & 0xF] | (bit_interleave_table[fill >> 4] << 2); } B >>= num3; n <<= num3; while ((n & 1) == 0 && num6 < 0) { if (!lowband.IsEmpty) { haar1(lowband, lowband_ptr, n, B); } fill |= fill << B; B <<= 1; n >>= 1; num2++; num6++; } num = B; int num7 = n; if (num > 1 && !lowband.IsEmpty) { deinterleave_hadamard(lowband, lowband_ptr, n >> num3, num << num3, hadamard); } num4 = quant_partition_decode(ctx, encodedData, X, X_ptr, N, b, B, lowband, lowband_ptr, LM, gain, fill); if (num5 != 0) { if (num > 1) { interleave_hadamard(X, X_ptr, n >> num3, num << num3, hadamard); } n = num7; B = num; for (int i = 0; i < num2; i++) { B >>= 1; n <<= 1; num4 |= num4 >> B; haar1(X, X_ptr, n, B); } for (int i = 0; i < num3; i++) { num4 = bit_deinterleave_table[num4]; haar1(X, X_ptr, N >> i, 1 << i); } B <<= num3; if (!lowband_out.IsEmpty) { int a = Inlines.celt_sqrt(Inlines.SHL32(N, 22)); for (int j = 0; j < N; j++) { lowband_out[lowband_out_ptr + j] = Inlines.MULT16_16_Q15(a, X[X_ptr + j]); } } num4 &= (uint)((1 << B) - 1); } return num4; } internal static uint quant_band_stereo_encode(band_ctx ctx, Span encodedData, Span X, int X_ptr, Span Y, int Y_ptr, int N, int b, int B, Span lowband, int lowband_ptr, int LM, Span lowband_out, int lowband_out_ptr, Span lowband_scratch, int lowband_scratch_ptr, int fill) { int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; uint num5 = 0u; int num6 = 0; split_ctx split_ctx = new split_ctx(); EntropyCoder ec = ctx.ec; if (N == 1) { return quant_band_n1_encode(ctx, encodedData, X, X_ptr, Y, Y_ptr, b, lowband_out, lowband_out_ptr); } int fill2 = fill; compute_theta_encode(ctx, split_ctx, encodedData, X, X_ptr, Y, Y_ptr, N, ref b, B, B, LM, 1, ref fill); num2 = split_ctx.inv; num = split_ctx.imid; int iside = split_ctx.iside; int delta = split_ctx.delta; int itheta = split_ctx.itheta; int qalloc = split_ctx.qalloc; num3 = num; num4 = iside; if (N == 2) { int num7 = 0; int num8 = b; int num9 = 0; if (itheta != 0 && itheta != 16384) { num9 = 8; } num8 -= num9; bool num10 = itheta > 8192; ctx.remaining_bits -= qalloc + num9; Span x; int num11; Span span; if (num10) { x = Y; num11 = Y_ptr; span = X; } else { x = X; num11 = X_ptr; span = Y; } if (num9 != 0) { num7 = ((x[num11] * span[Y_ptr + 1] - x[num11 + 1] * span[Y_ptr] < 0) ? 1 : 0); ec.enc_bits(encodedData, (uint)num7, 1u); } num7 = 1 - 2 * num7; num5 = quant_band_encode(ctx, encodedData, x, num11, N, num8, B, lowband, lowband_ptr, LM, lowband_out, lowband_out_ptr, 32767, lowband_scratch, lowband_scratch_ptr, fill2); span[Y_ptr] = -num7 * x[num11 + 1]; span[Y_ptr + 1] = num7 * x[num11]; if (num6 != 0) { X[X_ptr] = Inlines.MULT16_16_Q15(num3, X[X_ptr]); X[X_ptr + 1] = Inlines.MULT16_16_Q15(num3, X[X_ptr + 1]); Y[Y_ptr] = Inlines.MULT16_16_Q15(num4, Y[Y_ptr]); Y[Y_ptr + 1] = Inlines.MULT16_16_Q15(num4, Y[Y_ptr + 1]); int a = X[X_ptr]; X[X_ptr] = Inlines.SUB16(a, Y[Y_ptr]); Y[Y_ptr] = Inlines.ADD16(a, Y[Y_ptr]); a = X[X_ptr + 1]; X[X_ptr + 1] = Inlines.SUB16(a, Y[Y_ptr + 1]); Y[Y_ptr + 1] = Inlines.ADD16(a, Y[Y_ptr + 1]); } } else { int num8 = Inlines.IMAX(0, Inlines.IMIN(b, (b - delta) / 2)); int num9 = b - num8; ctx.remaining_bits -= qalloc; int remaining_bits = ctx.remaining_bits; if (num8 >= num9) { num5 = quant_band_encode(ctx, encodedData, X, X_ptr, N, num8, B, lowband, lowband_ptr, LM, lowband_out, lowband_out_ptr, 32767, lowband_scratch, lowband_scratch_ptr, fill); remaining_bits = num8 - (remaining_bits - ctx.remaining_bits); if (remaining_bits > 24 && itheta != 0) { num9 += remaining_bits - 24; } num5 |= quant_band_encode(ctx, encodedData, Y, Y_ptr, N, num9, B, null, 0, LM, null, 0, num4, null, 0, fill >> B); } else { num5 = quant_band_encode(ctx, encodedData, Y, Y_ptr, N, num9, B, null, 0, LM, null, 0, num4, null, 0, fill >> B); remaining_bits = num9 - (remaining_bits - ctx.remaining_bits); if (remaining_bits > 24 && itheta != 16384) { num8 += remaining_bits - 24; } num5 |= quant_band_encode(ctx, encodedData, X, X_ptr, N, num8, B, lowband, lowband_ptr, LM, lowband_out, lowband_out_ptr, 32767, lowband_scratch, lowband_scratch_ptr, fill); } } if (num6 != 0) { if (N != 2) { stereo_merge(X.Slice(X_ptr), Y.Slice(Y_ptr), num3, N); } if (num2 != 0) { for (int i = Y_ptr; i < N + Y_ptr; i++) { Y[i] = (short)(-Y[i]); } } } return num5; } internal static uint quant_band_stereo_decode(band_ctx ctx, ReadOnlySpan encodedData, Span X, int X_ptr, Span Y, int Y_ptr, int N, int b, int B, Span lowband, int lowband_ptr, int LM, Span lowband_out, int lowband_out_ptr, Span lowband_scratch, int lowband_scratch_ptr, int fill) { int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; uint num5 = 0u; int num6 = 1; split_ctx split_ctx = new split_ctx(); EntropyCoder ec = ctx.ec; if (N == 1) { return quant_band_n1_decode(ctx, encodedData, X, X_ptr, Y, Y_ptr, b, lowband_out, lowband_out_ptr); } int fill2 = fill; compute_theta_decode(ctx, split_ctx, encodedData, X, X_ptr, Y, Y_ptr, N, ref b, B, B, LM, 1, ref fill); num2 = split_ctx.inv; num = split_ctx.imid; int iside = split_ctx.iside; int delta = split_ctx.delta; int itheta = split_ctx.itheta; int qalloc = split_ctx.qalloc; num3 = num; num4 = iside; if (N == 2) { int num7 = 0; int num8 = b; int num9 = 0; if (itheta != 0 && itheta != 16384) { num9 = 8; } num8 -= num9; bool num10 = itheta > 8192; ctx.remaining_bits -= qalloc + num9; Span x; int num11; Span span; if (num10) { x = Y; num11 = Y_ptr; span = X; } else { x = X; num11 = X_ptr; span = Y; } if (num9 != 0) { num7 = (int)ec.dec_bits(encodedData, 1u); } num7 = 1 - 2 * num7; num5 = quant_band_decode(ctx, encodedData, x, num11, N, num8, B, lowband, lowband_ptr, LM, lowband_out, lowband_out_ptr, 32767, lowband_scratch, lowband_scratch_ptr, fill2); span[Y_ptr] = -num7 * x[num11 + 1]; span[Y_ptr + 1] = num7 * x[num11]; if (num6 != 0) { X[X_ptr] = Inlines.MULT16_16_Q15(num3, X[X_ptr]); X[X_ptr + 1] = Inlines.MULT16_16_Q15(num3, X[X_ptr + 1]); Y[Y_ptr] = Inlines.MULT16_16_Q15(num4, Y[Y_ptr]); Y[Y_ptr + 1] = Inlines.MULT16_16_Q15(num4, Y[Y_ptr + 1]); int a = X[X_ptr]; X[X_ptr] = Inlines.SUB16(a, Y[Y_ptr]); Y[Y_ptr] = Inlines.ADD16(a, Y[Y_ptr]); a = X[X_ptr + 1]; X[X_ptr + 1] = Inlines.SUB16(a, Y[Y_ptr + 1]); Y[Y_ptr + 1] = Inlines.ADD16(a, Y[Y_ptr + 1]); } } else { int num8 = Inlines.IMAX(0, Inlines.IMIN(b, (b - delta) / 2)); int num9 = b - num8; ctx.remaining_bits -= qalloc; int remaining_bits = ctx.remaining_bits; if (num8 >= num9) { num5 = quant_band_decode(ctx, encodedData, X, X_ptr, N, num8, B, lowband, lowband_ptr, LM, lowband_out, lowband_out_ptr, 32767, lowband_scratch, lowband_scratch_ptr, fill); remaining_bits = num8 - (remaining_bits - ctx.remaining_bits); if (remaining_bits > 24 && itheta != 0) { num9 += remaining_bits - 24; } num5 |= quant_band_decode(ctx, encodedData, Y, Y_ptr, N, num9, B, null, 0, LM, null, 0, num4, null, 0, fill >> B); } else { num5 = quant_band_decode(ctx, encodedData, Y, Y_ptr, N, num9, B, null, 0, LM, null, 0, num4, null, 0, fill >> B); remaining_bits = num9 - (remaining_bits - ctx.remaining_bits); if (remaining_bits > 24 && itheta != 16384) { num8 += remaining_bits - 24; } num5 |= quant_band_decode(ctx, encodedData, X, X_ptr, N, num8, B, lowband, lowband_ptr, LM, lowband_out, lowband_out_ptr, 32767, lowband_scratch, lowband_scratch_ptr, fill); } } if (num6 != 0) { if (N != 2) { stereo_merge(X.Slice(X_ptr), Y.Slice(Y_ptr), num3, N); } if (num2 != 0) { for (int i = Y_ptr; i < N + Y_ptr; i++) { Y[i] = (short)(-Y[i]); } } } return num5; } internal static void quant_all_bands_encode(int encode, CeltMode m, int start, int end, int[] X_, int[] Y_, byte[] collapse_masks, int[][] bandE, int[] pulses, int shortBlocks, int spread, int dual_stereo, int intensity, int[] tf_res, int total_bits, int balance, EntropyCoder ec, Span encodedData, int LM, int codedBands, ref uint seed) { short[] eBands = m.eBands; int num = 1; int num2 = ((Y_ == null) ? 1 : 2); int num3 = ((encode == 0) ? 1 : 0); band_ctx band_ctx = new band_ctx(); int num4 = 1 << LM; int num5 = ((shortBlocks == 0) ? 1 : num4); int num6 = num4 * eBands[start]; int[] array = new int[num2 * (num4 * eBands[m.nbEBands - 1] - num6)]; int num7 = num4 * eBands[m.nbEBands - 1] - num6; int[] array2 = X_; int lowband_scratch_ptr = num4 * eBands[m.nbEBands - 1]; int num8 = 0; band_ctx.bandE = bandE; band_ctx.ec = ec; band_ctx.encode = encode; band_ctx.intensity = intensity; band_ctx.m = m; band_ctx.seed = seed; band_ctx.spread = spread; for (int i = start; i < end; i++) { int num9 = -1; int num10 = 0; int num11 = 0; band_ctx.i = i; int num12 = ((i == end - 1) ? 1 : 0); int[] array3 = X_; int x_ptr = num4 * eBands[i]; int[] array4; if (Y_ != null) { array4 = Y_; num10 = num4 * eBands[i]; } else { array4 = null; } int num13 = num4 * eBands[i + 1] - num4 * eBands[i]; int num14 = (int)ec.tell_frac(); if (i != start) { balance -= num14; } int num15 = (band_ctx.remaining_bits = total_bits - num14 - 1); int num17; if (i <= codedBands - 1) { int num16 = Inlines.celt_sudiv(balance, Inlines.IMIN(3, codedBands - i)); num17 = Inlines.IMAX(0, Inlines.IMIN(16383, Inlines.IMIN(num15 + 1, pulses[i] + num16))); } else { num17 = 0; } if (num3 != 0 && num4 * eBands[i] - num13 >= num4 * eBands[start] && (num != 0 || num8 == 0)) { num8 = i; } num11 = (band_ctx.tf_change = tf_res[i]); if (i >= m.effEBands) { array3 = array; x_ptr = 0; if (Y_ != null) { array4 = array; num10 = 0; } array2 = null; } if (i == end - 1) { array2 = null; } uint num21; uint num20; if (num8 != 0 && (spread != 3 || num5 > 1 || num11 < 0)) { num9 = Inlines.IMAX(0, num4 * eBands[num8] - num6 - num13); int num18 = num8; while (num4 * eBands[--num18] > num9 + num6) { } int num19 = num8 - 1; while (num4 * eBands[++num19] < num9 + num6 + num13) { } num21 = (num20 = 0u); int num22 = num18; do { num21 |= collapse_masks[num22 * num2]; num20 |= collapse_masks[num22 * num2 + num2 - 1]; } while (++num22 < num19); } else { num21 = (num20 = (uint)((1 << num5) - 1)); } if (dual_stereo != 0 && i == intensity) { dual_stereo = 0; if (num3 != 0) { for (int j = 0; j < num4 * eBands[i] - num6; j++) { array[j] = Inlines.HALF32(array[j] + array[num7 + j]); } } } if (dual_stereo != 0) { num21 = quant_band_encode(band_ctx, encodedData, array3, x_ptr, num13, num17 / 2, num5, (num9 != -1) ? array : null, num9, LM, (num12 != 0) ? null : array, num4 * eBands[i] - num6, 32767, array2, lowband_scratch_ptr, (int)num21); num20 = quant_band_encode(band_ctx, encodedData, array4, num10, num13, num17 / 2, num5, (num9 != -1) ? array : null, num7 + num9, LM, (num12 != 0) ? null : array, num7 + (num4 * eBands[i] - num6), 32767, array2, lowband_scratch_ptr, (int)num20); } else { num21 = ((array4 == null) ? quant_band_encode(band_ctx, encodedData, array3, x_ptr, num13, num17, num5, (num9 != -1) ? array : null, num9, LM, (num12 != 0) ? null : array, num4 * eBands[i] - num6, 32767, array2, lowband_scratch_ptr, (int)(num21 | num20)) : quant_band_stereo_encode(band_ctx, encodedData, array3, x_ptr, array4, num10, num13, num17, num5, (num9 != -1) ? array : null, num9, LM, (num12 != 0) ? null : array, num4 * eBands[i] - num6, array2, lowband_scratch_ptr, (int)(num21 | num20))); num20 = num21; } collapse_masks[i * num2] = (byte)(num21 & 0xFFu); collapse_masks[i * num2 + num2 - 1] = (byte)(num20 & 0xFFu); balance += pulses[i] + num14; num = ((num17 > num13 << 3) ? 1 : 0); } seed = band_ctx.seed; } internal static void quant_all_bands_decode(int encode, CeltMode m, int start, int end, int[] X_, int[] Y_, byte[] collapse_masks, int[][] bandE, int[] pulses, int shortBlocks, int spread, int dual_stereo, int intensity, int[] tf_res, int total_bits, int balance, EntropyCoder ec, ReadOnlySpan encodedData, int LM, int codedBands, ref uint seed) { short[] eBands = m.eBands; int num = 1; int num2 = ((Y_ == null) ? 1 : 2); int num3 = ((encode == 0) ? 1 : 0); band_ctx band_ctx = new band_ctx(); int num4 = 1 << LM; int num5 = ((shortBlocks == 0) ? 1 : num4); int num6 = num4 * eBands[start]; int[] array = new int[num2 * (num4 * eBands[m.nbEBands - 1] - num6)]; int num7 = num4 * eBands[m.nbEBands - 1] - num6; int[] array2 = X_; int lowband_scratch_ptr = num4 * eBands[m.nbEBands - 1]; int num8 = 0; band_ctx.bandE = bandE; band_ctx.ec = ec; band_ctx.encode = encode; band_ctx.intensity = intensity; band_ctx.m = m; band_ctx.seed = seed; band_ctx.spread = spread; for (int i = start; i < end; i++) { int num9 = -1; int num10 = 0; int num11 = 0; band_ctx.i = i; int num12 = ((i == end - 1) ? 1 : 0); int[] array3 = X_; int x_ptr = num4 * eBands[i]; int[] array4; if (Y_ != null) { array4 = Y_; num10 = num4 * eBands[i]; } else { array4 = null; } int num13 = num4 * eBands[i + 1] - num4 * eBands[i]; int num14 = (int)ec.tell_frac(); if (i != start) { balance -= num14; } int num15 = (band_ctx.remaining_bits = total_bits - num14 - 1); int num17; if (i <= codedBands - 1) { int num16 = Inlines.celt_sudiv(balance, Inlines.IMIN(3, codedBands - i)); num17 = Inlines.IMAX(0, Inlines.IMIN(16383, Inlines.IMIN(num15 + 1, pulses[i] + num16))); } else { num17 = 0; } if (num3 != 0 && num4 * eBands[i] - num13 >= num4 * eBands[start] && (num != 0 || num8 == 0)) { num8 = i; } num11 = (band_ctx.tf_change = tf_res[i]); if (i >= m.effEBands) { array3 = array; x_ptr = 0; if (Y_ != null) { array4 = array; num10 = 0; } array2 = null; } if (i == end - 1) { array2 = null; } uint num21; uint num20; if (num8 != 0 && (spread != 3 || num5 > 1 || num11 < 0)) { num9 = Inlines.IMAX(0, num4 * eBands[num8] - num6 - num13); int num18 = num8; while (num4 * eBands[--num18] > num9 + num6) { } int num19 = num8 - 1; while (num4 * eBands[++num19] < num9 + num6 + num13) { } num21 = (num20 = 0u); int num22 = num18; do { num21 |= collapse_masks[num22 * num2]; num20 |= collapse_masks[num22 * num2 + num2 - 1]; } while (++num22 < num19); } else { num21 = (num20 = (uint)((1 << num5) - 1)); } if (dual_stereo != 0 && i == intensity) { dual_stereo = 0; if (num3 != 0) { for (int j = 0; j < num4 * eBands[i] - num6; j++) { array[j] = Inlines.HALF32(array[j] + array[num7 + j]); } } } if (dual_stereo != 0) { num21 = quant_band_decode(band_ctx, encodedData, array3, x_ptr, num13, num17 / 2, num5, (num9 != -1) ? array : null, num9, LM, (num12 != 0) ? null : array, num4 * eBands[i] - num6, 32767, array2, lowband_scratch_ptr, (int)num21); num20 = quant_band_decode(band_ctx, encodedData, array4, num10, num13, num17 / 2, num5, (num9 != -1) ? array : null, num7 + num9, LM, (num12 != 0) ? null : array, num7 + (num4 * eBands[i] - num6), 32767, array2, lowband_scratch_ptr, (int)num20); } else { num21 = ((array4 == null) ? quant_band_decode(band_ctx, encodedData, array3, x_ptr, num13, num17, num5, (num9 != -1) ? array : null, num9, LM, (num12 != 0) ? null : array, num4 * eBands[i] - num6, 32767, array2, lowband_scratch_ptr, (int)(num21 | num20)) : quant_band_stereo_decode(band_ctx, encodedData, array3, x_ptr, array4, num10, num13, num17, num5, (num9 != -1) ? array : null, num9, LM, (num12 != 0) ? null : array, num4 * eBands[i] - num6, array2, lowband_scratch_ptr, (int)(num21 | num20))); num20 = num21; } collapse_masks[i * num2] = (byte)(num21 & 0xFFu); collapse_masks[i * num2 + num2 - 1] = (byte)(num20 & 0xFFu); balance += pulses[i] + num14; num = ((num17 > num13 << 3) ? 1 : 0); } seed = band_ctx.seed; } } internal class CeltCommon { private static readonly byte[] inv_table = new byte[128] { 255, 255, 156, 110, 86, 70, 59, 51, 45, 40, 37, 33, 31, 28, 26, 25, 23, 22, 21, 20, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12, 12, 12, 11, 11, 11, 10, 10, 10, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2 }; private static readonly short[][] gains = new short[3][] { new short[3] { 10048, 7112, 4248 }, new short[3] { 15200, 8784, 0 }, new short[3] { 26208, 3280, 0 } }; private static readonly sbyte[][] tf_select_table = new sbyte[4][] { new sbyte[8] { 0, -1, 0, -1, 0, -1, 0, -1 }, new sbyte[8] { 0, -1, 0, -2, 1, 0, 1, -1 }, new sbyte[8] { 0, -2, 0, -3, 2, 0, 1, -1 }, new sbyte[8] { 0, -2, 0, -3, 3, 0, 1, -1 } }; internal static int compute_vbr(CeltMode mode, AnalysisInfo analysis, int base_target, int LM, int bitrate, int lastCodedBands, int C, int intensity, int constrained_vbr, int stereo_saving, int tot_boost, int tf_estimate, int pitch_change, int maxDepth, OpusFramesize variable_duration, int lfe, int has_surround_mask, int surround_masking, int temporal_vbr) { int nbEBands = mode.nbEBands; short[] eBands = mode.eBands; int num = ((lastCodedBands != 0) ? lastCodedBands : nbEBands); int num2 = eBands[num] << LM; if (C == 2) { num2 += eBands[Inlines.IMIN(intensity, num)] << LM; } int num3 = base_target; if (analysis.valid != 0 && (double)analysis.activity < 0.4) { num3 -= (int)((float)(num2 << 3) * (0.4f - analysis.activity)); } if (C == 2) { int num4 = Inlines.IMIN(intensity, num); int num5 = (eBands[num4] << LM) - num4; int a = Inlines.DIV32_16(Inlines.MULT16_16(26214, num5), num2); stereo_saving = Inlines.MIN16(stereo_saving, 256); num3 -= Inlines.MIN32(Inlines.MULT16_32_Q15(a, num3), Inlines.SHR32(Inlines.MULT16_16(stereo_saving - 26, num5 << 3), 8)); } num3 += tot_boost - (16 << LM); int num6 = ((variable_duration == OpusFramesize.OPUS_FRAMESIZE_VARIABLE) ? 328 : 655); num3 += Inlines.SHL32(Inlines.MULT16_32_Q15(tf_estimate - num6, num3), 1); if (analysis.valid != 0 && lfe == 0) { float num7 = Inlines.MAX16(0f, analysis.tonality - 0.15f) - 0.09f; int num8 = num3 + (int)((float)(num2 << 3) * 1.2f * num7); if (pitch_change != 0) { num8 += (int)((float)(num2 << 3) * 0.8f); } num3 = num8; } if (has_surround_mask != 0 && lfe == 0) { int b = num3 + Inlines.SHR32(Inlines.MULT16_16(surround_masking, num2 << 3), 10); num3 = Inlines.IMAX(num3 / 4, b); } int num9 = eBands[nbEBands - 2] << LM; int a2 = Inlines.SHR32(Inlines.MULT16_16(C * num9 << 3, maxDepth), 10); a2 = Inlines.IMAX(a2, num3 >> 2); num3 = Inlines.IMIN(num3, a2); if ((has_surround_mask == 0 || lfe != 0) && (constrained_vbr != 0 || bitrate < 64000)) { int a3 = Inlines.MAX16(0, bitrate - 32000); if (constrained_vbr != 0) { a3 = Inlines.MIN16(a3, 21955); } num3 = base_target + Inlines.MULT16_32_Q15(a3, num3 - base_target); } if (has_surround_mask == 0 && tf_estimate < 3277) { int b2 = Inlines.MULT16_16_Q15(3329, Inlines.IMAX(0, Inlines.IMIN(32000, 96000 - bitrate))); int a4 = Inlines.SHR32(Inlines.MULT16_16(temporal_vbr, b2), 10); num3 += Inlines.MULT16_32_Q15(a4, num3); } return Inlines.IMIN(2 * base_target, num3); } internal static int transient_analysis(int[][] input, int len, int C, out int tf_estimate, out int tf_chan) { int num = 0; tf_chan = 0; int[] array = new int[len]; int num2 = len / 2; for (int i = 0; i < C; i++) { int num3 = 0; int a = 0; int num4 = 0; for (int j = 0; j < len; j++) { int num5 = Inlines.SHR32(input[i][j], 12); int num6 = Inlines.ADD32(a, num5); a = num4 + num6 - Inlines.SHL32(num5, 1); num4 = num5 - Inlines.SHR32(num6, 1); array[j] = Inlines.EXTRACT16(Inlines.SHR32(num6, 2)); } Arrays.MemSetInt(array, 0, 12); int num7 = 0; num7 = 14 - Inlines.celt_ilog2(1 + Inlines.celt_maxabs32(array, 0, len)); if (num7 != 0) { for (int j = 0; j < len; j++) { array[j] = Inlines.SHL16(array[j], num7); } } int num8 = 0; a = 0; for (int j = 0; j < num2; j++) { int num9 = Inlines.PSHR32(Inlines.MULT16_16(array[2 * j], array[2 * j]) + Inlines.MULT16_16(array[2 * j + 1], array[2 * j + 1]), 16); num8 += num9; array[j] = a + Inlines.PSHR32(num9 - a, 4); a = array[j]; } a = 0; int a2 = 0; for (int j = num2 - 1; j >= 0; j--) { array[j] = a + Inlines.PSHR32(array[j] - a, 3); a = array[j]; a2 = Inlines.MAX16(a2, a); } num8 = Inlines.MULT16_16(Inlines.celt_sqrt(num8), Inlines.celt_sqrt(Inlines.MULT16_16(a2, num2 >> 1))); int b = Inlines.SHL32(num2, 20) / Inlines.ADD32(1, Inlines.SHR32(num8, 1)); num3 = 0; for (int j = 12; j < num2 - 5; j += 4) { int num10 = Inlines.MAX32(0, Inlines.MIN32(127, Inlines.MULT16_32_Q15(array[j] + 1, b))); num3 += inv_table[num10]; } num3 = 64 * num3 * 4 / (6 * (num2 - 17)); if (num3 > num) { tf_chan = i; num = num3; } } bool result = num > 200; int b2 = Inlines.MAX16(0, Inlines.celt_sqrt(27 * num) - 42); tf_estimate = Inlines.celt_sqrt(Inlines.MAX32(0, Inlines.SHL32(Inlines.MULT16_16(113, Inlines.MIN16(163, b2)), 14) - 37312528)); return result ? 1 : 0; } internal static int patch_transient_decision(int[][] newE, int[][] oldE, int nbEBands, int start, int end, int C) { int a = 0; int[] array = new int[26]; if (C == 1) { array[start] = oldE[0][start]; for (int i = start + 1; i < end; i++) { array[i] = Inlines.MAX16(array[i - 1] - 1024, oldE[0][i]); } } else { array[start] = Inlines.MAX16(oldE[0][start], oldE[1][start]); for (int i = start + 1; i < end; i++) { array[i] = Inlines.MAX16(array[i - 1] - 1024, Inlines.MAX16(oldE[0][i], oldE[1][i])); } } for (int i = end - 2; i >= start; i--) { array[i] = Inlines.MAX16(array[i], array[i + 1] - 1024); } int num = 0; do { for (int i = Inlines.IMAX(2, start); i < end - 1; i++) { int a2 = Inlines.MAX16(0, newE[num][i]); int b = Inlines.MAX16(0, array[i]); a = Inlines.ADD32(a, Inlines.MAX16(0, Inlines.SUB16(a2, b))); } } while (++num < C); a = Inlines.DIV32(a, C * (end - 1 - Inlines.IMAX(2, start))); return (a > 1024) ? 1 : 0; } internal static void compute_mdcts(CeltMode mode, int shortBlocks, int[][] input, int[][] output, int C, int CC, int LM, int upsample) { int overlap = mode.overlap; int num; int num2; int shift; if (shortBlocks != 0) { num = shortBlocks; num2 = mode.shortMdctSize; shift = mode.maxLM; } else { num = 1; num2 = mode.shortMdctSize << LM; shift = mode.maxLM - LM; } int num3 = 0; do { for (int i = 0; i < num; i++) { MDCT.clt_mdct_forward(mode.mdct, input[num3], i * num2, output[num3], i, mode.window, overlap, shift, num); } } while (++num3 < CC); if (CC == 2 && C == 1) { for (int j = 0; j < num * num2; j++) { output[0][j] = Inlines.ADD32(Inlines.HALF32(output[0][j]), Inlines.HALF32(output[1][j])); } } if (upsample == 1) { return; } num3 = 0; do { int num4 = num * num2 / upsample; for (int j = 0; j < num4; j++) { output[num3][j] *= upsample; } Arrays.MemSetWithOffset(output[num3], 0, num4, num * num2 - num4); } while (++num3 < C); } internal static void celt_preemphasis(Span pcmp, int pcmp_ptr, Span inp, int inp_ptr, int N, int CC, int upsample, int[] coef, ref int mem, int clip) { int a = coef[0]; int num = mem; if (coef[1] == 0 && upsample == 1 && clip == 0) { for (int i = 0; i < N; i++) { int num2 = pcmp[pcmp_ptr + CC * i]; inp[inp_ptr + i] = Inlines.SHL32(num2, 12) - num; num = Inlines.SHR32(Inlines.MULT16_16(a, num2), 3); } mem = num; return; } int num3 = N / upsample; if (upsample != 1) { Arrays.MemSetWithOffset(inp, 0, inp_ptr, N); } for (int i = 0; i < num3; i++) { inp[inp_ptr + i * upsample] = pcmp[pcmp_ptr + CC * i]; } for (int i = 0; i < N; i++) { int num4 = inp[inp_ptr + i]; inp[inp_ptr + i] = Inlines.SHL32(num4, 12) - num; num = Inlines.SHR32(Inlines.MULT16_16(a, num4), 3); } mem = num; } internal static void celt_preemphasis(short[] pcmp, Span inp, int inp_ptr, int N, int CC, int upsample, int[] coef, BoxedValueInt mem, int clip) { int a = coef[0]; int num = mem.Val; if (coef[1] == 0 && upsample == 1 && clip == 0) { for (int i = 0; i < N; i++) { int num2 = pcmp[CC * i]; inp[inp_ptr + i] = Inlines.SHL32(num2, 12) - num; num = Inlines.SHR32(Inlines.MULT16_16(a, num2), 3); } mem.Val = num; return; } int num3 = N / upsample; if (upsample != 1) { Arrays.MemSetWithOffset(inp, 0, inp_ptr, N); } for (int i = 0; i < num3; i++) { inp[inp_ptr + i * upsample] = pcmp[CC * i]; } for (int i = 0; i < N; i++) { int num4 = inp[inp_ptr + i]; inp[inp_ptr + i] = Inlines.SHL32(num4, 12) - num; num = Inlines.SHR32(Inlines.MULT16_16(a, num4), 3); } mem.Val = num; } internal static int l1_metric(int[] tmp, int N, int LM, int bias) { int num = 0; for (int i = 0; i < N; i++) { num += Inlines.EXTEND32(Inlines.ABS32(tmp[i])); } return Inlines.MAC16_32_Q15(num, LM * bias, num); } internal static int tf_analysis(CeltMode m, int len, int isTransient, int[] tf_res, int lambda, int[][] X, int N0, int LM, out int tf_sum, int tf_estimate, int tf_chan) { int[] array = new int[2]; int num = 0; int bias = Inlines.MULT16_16_Q14(1311, Inlines.MAX16(-4096, 8192 - tf_estimate)); int[] array2 = new int[len]; int[] array3 = new int[m.eBands[len] - m.eBands[len - 1] << LM]; int[] array4 = new int[m.eBands[len] - m.eBands[len - 1] << LM]; int[] array5 = new int[len]; int[] array6 = new int[len]; tf_sum = 0; for (int i = 0; i < len; i++) { int num2 = 0; int num3 = m.eBands[i + 1] - m.eBands[i] << LM; int num4 = ((m.eBands[i + 1] - m.eBands[i] == 1) ? 1 : 0); Arrays.MemCopy(X[tf_chan], m.eBands[i] << LM, array3, 0, num3); int num5 = l1_metric(array3, num3, (isTransient != 0) ? LM : 0, bias); int num6 = num5; if (isTransient != 0 && num4 == 0) { Arrays.MemCopy(array3, 0, array4, 0, num3); Bands.haar1ZeroOffset(array4, num3 >> LM, 1 << LM); num5 = l1_metric(array4, num3, LM + 1, bias); if (num5 < num6) { num6 = num5; num2 = -1; } } for (int j = 0; j < LM + ((isTransient == 0 && num4 == 0) ? 1 : 0); j++) { int lM = ((isTransient == 0) ? (j + 1) : (LM - j - 1)); Bands.haar1ZeroOffset(array3, num3 >> j, 1 << j); num5 = l1_metric(array3, num3, lM, bias); if (num5 < num6) { num6 = num5; num2 = j + 1; } } if (isTransient != 0) { array2[i] = 2 * num2; } else { array2[i] = -2 * num2; } tf_sum += ((isTransient != 0) ? LM : 0) - array2[i] / 2; if (num4 != 0 && (array2[i] == 0 || array2[i] == -2 * LM)) { array2[i]--; } } num = 0; int num7; int num8; for (int k = 0; k < 2; k++) { num7 = 0; num8 = ((isTransient == 0) ? lambda : 0); for (int i = 1; i < len; i++) { int num9 = Inlines.IMIN(num7, num8 + lambda); int num10 = Inlines.IMIN(num7 + lambda, num8); num7 = num9 + Inlines.abs(array2[i] - 2 * Tables.tf_select_table[LM][4 * isTransient + 2 * k]); num8 = num10 + Inlines.abs(array2[i] - 2 * Tables.tf_select_table[LM][4 * isTransient + 2 * k + 1]); } num7 = Inlines.IMIN(num7, num8); array[k] = num7; } if (array[1] < array[0] && isTransient != 0) { num = 1; } num7 = 0; num8 = ((isTransient == 0) ? lambda : 0); for (int i = 1; i < len; i++) { int num11 = num7; int num12 = num8 + lambda; int num13; if (num11 < num12) { num13 = num11; array5[i] = 0; } else { num13 = num12; array5[i] = 1; } num11 = num7 + lambda; num12 = num8; int num14; if (num11 < num12) { num14 = num11; array6[i] = 0; } else { num14 = num12; array6[i] = 1; } num7 = num13 + Inlines.abs(array2[i] - 2 * Tables.tf_select_table[LM][4 * isTransient + 2 * num]); num8 = num14 + Inlines.abs(array2[i] - 2 * Tables.tf_select_table[LM][4 * isTransient + 2 * num + 1]); } tf_res[len - 1] = ((num7 >= num8) ? 1 : 0); for (int i = len - 2; i >= 0; i--) { if (tf_res[i + 1] == 1) { tf_res[i] = array6[i + 1]; } else { tf_res[i] = array5[i + 1]; } } return num; } internal static void tf_encode(int start, int end, int isTransient, int[] tf_res, int LM, int tf_select, EntropyCoder enc, Span encodedData) { uint num = enc.storage * 8; uint num2 = (uint)enc.tell(); int num3 = ((isTransient != 0) ? 2 : 4); int num4 = ((LM > 0 && num2 + num3 + 1 <= num) ? 1 : 0); num -= (uint)num4; int num5; int num6 = (num5 = 0); for (int i = start; i < end; i++) { if (num2 + num3 <= num) { enc.enc_bit_logp(encodedData, tf_res[i] ^ num6, (uint)num3); num2 = (uint)enc.tell(); num6 = tf_res[i]; num5 |= num6; } else { tf_res[i] = num6; } num3 = ((isTransient != 0) ? 4 : 5); } if (num4 != 0 && Tables.tf_select_table[LM][4 * isTransient + num5] != Tables.tf_select_table[LM][4 * isTransient + 2 + num5]) { enc.enc_bit_logp(encodedData, tf_select, 1u); } else { tf_select = 0; } for (int i = start; i < end; i++) { tf_res[i] = Tables.tf_select_table[LM][4 * isTransient + 2 * tf_select + tf_res[i]]; } } internal static int alloc_trim_analysis(CeltMode m, int[][] X, int[][] bandLogE, int end, int LM, int C, AnalysisInfo analysis, ref int stereo_saving, int tf_estimate, int intensity, int surround_trim) { int num = 0; int num2 = 1280; if (C == 2) { int num3 = 0; Span span; for (int i = 0; i < 8; i++) { span = X[0].AsSpan(); Span x = span.Slice(m.eBands[i] << LM); span = X[1].AsSpan(); int a = Kernels.celt_inner_prod(x, span.Slice(m.eBands[i] << LM), m.eBands[i + 1] - m.eBands[i] << LM); num3 = Inlines.ADD16(num3, Inlines.EXTRACT16(Inlines.SHR32(a, 18))); } num3 = Inlines.MULT16_16_Q15(4096, num3); num3 = Inlines.MIN16(1024, Inlines.ABS32(num3)); int num4 = num3; for (int i = 8; i < intensity; i++) { span = X[0].AsSpan(); Span x2 = span.Slice(m.eBands[i] << LM); span = X[1].AsSpan(); int a2 = Kernels.celt_inner_prod(x2, span.Slice(m.eBands[i] << LM), m.eBands[i + 1] - m.eBands[i] << LM); num4 = Inlines.MIN16(num4, Inlines.ABS16(Inlines.EXTRACT16(Inlines.SHR32(a2, 18)))); } num4 = Inlines.MIN16(1024, Inlines.ABS32(num4)); int num5 = Inlines.celt_log2(1049625 - Inlines.MULT16_16(num3, num3)); int num6 = Inlines.MAX16(Inlines.HALF16(num5), Inlines.celt_log2(1049625 - Inlines.MULT16_16(num4, num4))); num5 = Inlines.PSHR32(num5 - 6144, 2); num6 = Inlines.PSHR32(num6 - 6144, 2); num2 += Inlines.MAX16(-1024, Inlines.MULT16_16_Q15(24576, num5)); stereo_saving = Inlines.MIN16(stereo_saving + 64, -Inlines.HALF16(num6)); } int num7 = 0; do { for (int i = 0; i < end - 1; i++) { num += bandLogE[num7][i] * (2 + 2 * i - end); } } while (++num7 < C); num /= C * (end - 1); num2 -= Inlines.MAX16(Inlines.NEG16((short)512), Inlines.MIN16(512, Inlines.SHR16(num + 1024, 2) / 6)); num2 -= Inlines.SHR16(surround_trim, 2); num2 -= 2 * Inlines.SHR16(tf_estimate, 6); if (analysis.valid != 0) { num2 -= Inlines.MAX16(-512, Inlines.MIN16(512, (int)(512f * (analysis.tonality_slope + 0.05f)))); } int b = Inlines.PSHR32(num2, 8); return Inlines.IMAX(0, Inlines.IMIN(10, b)); } internal static int stereo_analysis(CeltMode m, int[][] X, int LM) { int num = 1; int num2 = 1; for (int i = 0; i < 13; i++) { for (int j = m.eBands[i] << LM; j < m.eBands[i + 1] << LM; j++) { int num3 = Inlines.EXTEND32(X[0][j]); int num4 = Inlines.EXTEND32(X[1][j]); int x = Inlines.ADD32(num3, num4); int x2 = Inlines.SUB32(num3, num4); num = Inlines.ADD32(num, Inlines.ADD32(Inlines.ABS32(num3), Inlines.ABS32(num4))); num2 = Inlines.ADD32(num2, Inlines.ADD32(Inlines.ABS32(x), Inlines.ABS32(x2))); } } num2 = Inlines.MULT16_32_Q15((short)23170, num2); int num5 = 13; if (LM <= 1) { num5 -= 8; } return (Inlines.MULT16_32_Q15((m.eBands[13] << LM + 1) + num5, num2) > Inlines.MULT16_32_Q15(m.eBands[13] << LM + 1, num)) ? 1 : 0; } internal static int median_of_5(Span x, int x_ptr) { int num = x[x_ptr + 2]; int num3; int num2; if (x[x_ptr] > x[x_ptr + 1]) { num2 = x[x_ptr + 1]; num3 = x[x_ptr]; } else { num2 = x[x_ptr]; num3 = x[x_ptr + 1]; } int num4; int num5; if (x[x_ptr + 3] > x[x_ptr + 4]) { num4 = x[x_ptr + 4]; num5 = x[x_ptr + 3]; } else { num4 = x[x_ptr + 3]; num5 = x[x_ptr + 4]; } if (num2 > num4) { int num6 = num4; num4 = num2; num2 = num6; int num7 = num5; num5 = num3; num3 = num7; } if (num > num3) { if (num3 < num4) { return Inlines.MIN16(num, num4); } return Inlines.MIN16(num5, num3); } if (num < num4) { return Inlines.MIN16(num3, num4); } return Inlines.MIN16(num, num5); } internal static int median_of_3(Span x, int x_ptr) { int num; int num2; if (x[x_ptr] > x[x_ptr + 1]) { num = x[x_ptr + 1]; num2 = x[x_ptr]; } else { num = x[x_ptr]; num2 = x[x_ptr + 1]; } int num3 = x[x_ptr + 2]; if (num2 < num3) { return num2; } if (num < num3) { return num3; } return num; } internal static int dynalloc_analysis(int[][] bandLogE, int[][] bandLogE2, int nbEBands, int start, int end, int C, int[] offsets, int lsb_depth, short[] logN, int isTransient, int vbr, int constrained_vbr, short[] eBands, int LM, int effectiveBytes, out int tot_boost_, int lfe, int[] surround_dynalloc) { int num = 0; int[][] array = Arrays.InitTwoDimensionalArray(2, nbEBands); int[] array2 = new int[C * nbEBands]; Arrays.MemSetInt(offsets, 0, nbEBands); int num2 = -32666; for (int i = 0; i < end; i++) { array2[i] = Inlines.MULT16_16((short)64, logN[i]) + 512 + Inlines.SHL16(9 - lsb_depth, 10) - Inlines.SHL16(Tables.eMeans[i], 6) + Inlines.MULT16_16(6, (i + 5) * (i + 5)); } int num3 = 0; do { for (int i = 0; i < end; i++) { num2 = Inlines.MAX16(num2, bandLogE[num3][i] - array2[i]); } } while (++num3 < C); if (effectiveBytes > 50 && LM >= 1 && lfe == 0) { int num4 = 0; num3 = 0; do { int[] array3 = array[num3]; array3[0] = bandLogE2[num3][0]; for (int i = 1; i < end; i++) { if (bandLogE2[num3][i] > bandLogE2[num3][i - 1] + 512) { num4 = i; } array3[i] = Inlines.MIN16(array3[i - 1] + 1536, bandLogE2[num3][i]); } for (int i = num4 - 1; i >= 0; i--) { array3[i] = Inlines.MIN16(array3[i], Inlines.MIN16(array3[i + 1] + 2048, bandLogE2[num3][i])); } int num5 = 1024; for (int i = 2; i < end - 2; i++) { array3[i] = Inlines.MAX16(array3[i], median_of_5(bandLogE2[num3], i - 2) - num5); } int b = median_of_3(bandLogE2[num3], 0) - num5; array3[0] = Inlines.MAX16(array3[0], b); array3[1] = Inlines.MAX16(array3[1], b); b = median_of_3(bandLogE2[num3], end - 3) - num5; array3[end - 2] = Inlines.MAX16(array3[end - 2], b); array3[end - 1] = Inlines.MAX16(array3[end - 1], b); for (int i = 0; i < end; i++) { array3[i] = Inlines.MAX16(array3[i], array2[i]); } } while (++num3 < C); if (C == 2) { for (int i = start; i < end; i++) { array[1][i] = Inlines.MAX16(array[1][i], array[0][i] - 4096); array[0][i] = Inlines.MAX16(array[0][i], array[1][i] - 4096); array[0][i] = Inlines.HALF16(Inlines.MAX16(0, bandLogE[0][i] - array[0][i]) + Inlines.MAX16(0, bandLogE[1][i] - array[1][i])); } } else { for (int i = start; i < end; i++) { array[0][i] = Inlines.MAX16(0, bandLogE[0][i] - array[0][i]); } } for (int i = start; i < end; i++) { array[0][i] = Inlines.MAX16(array[0][i], surround_dynalloc[i]); } if ((vbr == 0 || constrained_vbr != 0) && isTransient == 0) { for (int i = start; i < end; i++) { array[0][i] = Inlines.HALF16(array[0][i]); } } for (int i = start; i < end; i++) { if (i < 8) { array[0][i] *= 2; } if (i >= 12) { array[0][i] = Inlines.HALF16(array[0][i]); } array[0][i] = Inlines.MIN16(array[0][i], 4096); int num6 = C * (eBands[i + 1] - eBands[i]) << LM; int num7; int num8; if (num6 < 6) { num7 = Inlines.SHR32(array[0][i], 10); num8 = num7 * num6 << 3; } else if (num6 > 48) { num7 = Inlines.SHR32(array[0][i] * 8, 10); num8 = (num7 * num6 << 3) / 8; } else { num7 = Inlines.SHR32(array[0][i] * num6 / 6, 10); num8 = num7 * 6 << 3; } if ((vbr == 0 || (constrained_vbr != 0 && isTransient == 0)) && num + num8 >> 3 >> 3 > effectiveBytes / 4) { int num9 = effectiveBytes / 4 << 3 << 3; offsets[i] = num9 - num; num = num9; break; } offsets[i] = num7; num += num8; } } tot_boost_ = num; return num2; } internal static void deemphasis(int[][] input, int[] input_ptrs, Span pcm, int pcm_ptr, int N, int C, int downsample, int[] coef, int[] mem, int accum) { int num = 0; if (downsample == 1 && C == 2 && accum == 0) { deemphasis_stereo_simple(input, input_ptrs, pcm, pcm_ptr, N, coef[0], mem); return; } int[] array = new int[N]; int a = coef[0]; int num2 = N / downsample; int num3 = 0; do { int num4 = mem[num3]; int[] array2 = input[num3]; int num5 = input_ptrs[num3]; int num6 = pcm_ptr + num3; if (downsample > 1) { for (int i = 0; i < N; i++) { int num7 = array2[num5 + i] + num4; num4 = Inlines.MULT16_32_Q15(a, num7); array[i] = num7; } num = 1; } else if (accum != 0) { for (int i = 0; i < N; i++) { int num8 = array2[num5 + i] + num4; num4 = Inlines.MULT16_32_Q15(a, num8); pcm[num6 + i * C] = Inlines.SAT16(Inlines.ADD32(pcm[num6 + i * C], Inlines.SIG2WORD16(num8))); } } else { for (int i = 0; i < N; i++) { int num9 = array2[num5 + i] + num4; if (array2[num5 + i] > 0 && num4 > 0 && num9 < 0) { num9 = int.MaxValue; num4 = int.MaxValue; } else { num4 = Inlines.MULT16_32_Q15(a, num9); } pcm[num6 + i * C] = Inlines.SIG2WORD16(num9); } } mem[num3] = num4; if (num != 0) { for (int i = 0; i < num2; i++) { pcm[num6 + i * C] = Inlines.SIG2WORD16(array[i * downsample]); } } } while (++num3 < C); } internal static void deemphasis_stereo_simple(int[][] input, int[] input_ptrs, Span pcm, int pcm_ptr, int N, int coef0, int[] mem) { int[] array = input[0]; int[] array2 = input[1]; int num = input_ptrs[0]; int num2 = input_ptrs[1]; int num3 = mem[0]; int num4 = mem[1]; for (int i = 0; i < N; i++) { int num5 = array[num + i] + num3; int num6 = array2[num2 + i] + num4; num3 = Inlines.MULT16_32_Q15(coef0, num5); num4 = Inlines.MULT16_32_Q15(coef0, num6); pcm[pcm_ptr + 2 * i] = Inlines.SIG2WORD16(num5); pcm[pcm_ptr + 2 * i + 1] = Inlines.SIG2WORD16(num6); } mem[0] = num3; mem[1] = num4; } internal static void celt_synthesis(CeltMode mode, int[][] X, int[][] out_syn, int[] out_syn_ptrs, int[] oldBandE, int start, int effEnd, int C, int CC, int isTransient, int LM, int downsample, int silence) { int overlap = mode.overlap; int nbEBands = mode.nbEBands; int num = mode.shortMdctSize << LM; int[] array = new int[num]; int num2 = 1 << LM; int num3; int num4; int shift; if (isTransient != 0) { num3 = num2; num4 = mode.shortMdctSize; shift = mode.maxLM; } else { num3 = 1; num4 = mode.shortMdctSize << LM; shift = mode.maxLM - LM; } if (CC == 2 && C == 1) { Bands.denormalise_bands(mode, X[0], array, 0, oldBandE, 0, start, effEnd, num2, downsample, silence); int num5 = out_syn_ptrs[1] + overlap / 2; Arrays.MemCopy(array, 0, out_syn[1], num5, num); for (int i = 0; i < num3; i++) { MDCT.clt_mdct_backward(mode.mdct, out_syn[1], num5 + i, out_syn[0], out_syn_ptrs[0] + num4 * i, mode.window, overlap, shift, num3); } for (int i = 0; i < num3; i++) { MDCT.clt_mdct_backward(mode.mdct, array, i, out_syn[1], out_syn_ptrs[1] + num4 * i, mode.window, overlap, shift, num3); } return; } if (CC == 1 && C == 2) { int num6 = out_syn_ptrs[0] + overlap / 2; Bands.denormalise_bands(mode, X[0], array, 0, oldBandE, 0, start, effEnd, num2, downsample, silence); Bands.denormalise_bands(mode, X[1], out_syn[0], num6, oldBandE, nbEBands, start, effEnd, num2, downsample, silence); for (int j = 0; j < num; j++) { array[j] = Inlines.HALF32(Inlines.ADD32(array[j], out_syn[0][num6 + j])); } for (int i = 0; i < num3; i++) { MDCT.clt_mdct_backward(mode.mdct, array, i, out_syn[0], out_syn_ptrs[0] + num4 * i, mode.window, overlap, shift, num3); } return; } int num7 = 0; do { Bands.denormalise_bands(mode, X[num7], array, 0, oldBandE, num7 * nbEBands, start, effEnd, num2, downsample, silence); for (int i = 0; i < num3; i++) { MDCT.clt_mdct_backward(mode.mdct, array, i, out_syn[num7], out_syn_ptrs[num7] + num4 * i, mode.window, overlap, shift, num3); } } while (++num7 < CC); } internal static void tf_decode(int start, int end, int isTransient, int[] tf_res, int LM, EntropyCoder dec, ReadOnlySpan encodedData) { uint num = dec.storage * 8; uint num2 = (uint)dec.tell(); int num3 = ((isTransient != 0) ? 2 : 4); int num4 = ((LM > 0 && num2 + num3 + 1 <= num) ? 1 : 0); num -= (uint)num4; int num5; int num6 = (num5 = 0); for (int i = start; i < end; i++) { if (num2 + num3 <= num) { num5 ^= dec.dec_bit_logp(encodedData, (uint)num3); num2 = (uint)dec.tell(); num6 |= num5; } tf_res[i] = num5; num3 = ((isTransient != 0) ? 4 : 5); } int num7 = 0; if (num4 != 0 && Tables.tf_select_table[LM][4 * isTransient + num6] != Tables.tf_select_table[LM][4 * isTransient + 2 + num6]) { num7 = dec.dec_bit_logp(encodedData, 1u); } for (int i = start; i < end; i++) { tf_res[i] = Tables.tf_select_table[LM][4 * isTransient + 2 * num7 + tf_res[i]]; } } internal static int celt_plc_pitch_search(int[][] decode_mem, int C) { int[] array = new int[1024]; Pitch.pitch_downsample(decode_mem, array, 2048, C); Pitch.pitch_search(array, 360, array, 1328, 620, out var pitch); return 720 - pitch; } internal static int resampling_factor(int rate) { return rate switch { 48000 => 1, 24000 => 2, 16000 => 3, 12000 => 4, 8000 => 6, _ => 0, }; } internal static void comb_filter_const(Span y, int y_ptr, Span x, int x_ptr, int T, int N, int g10, int g11, int g12) { int num = x_ptr - T; int b = x[num - 2]; int num2 = x[num - 1]; int num3 = x[num]; int num4 = x[num + 1]; for (int i = 0; i < N; i++) { int num5 = x[num + i + 2]; y[y_ptr + i] = x[x_ptr + i] + Inlines.MULT16_32_Q15(g10, num3) + Inlines.MULT16_32_Q15(g11, Inlines.ADD32(num4, num2)) + Inlines.MULT16_32_Q15(g12, Inlines.ADD32(num5, b)); b = num2; num2 = num3; num3 = num4; num4 = num5; } } internal static void comb_filter(Span y, int y_ptr, Span x, int x_ptr, int T0, int T1, int N, int g0, int g1, int tapset0, int tapset1, int[] window, int overlap) { if (g0 != 0 || g1 != 0) { int b = Inlines.MULT16_16_P15(g0, gains[tapset0][0]); int b2 = Inlines.MULT16_16_P15(g0, gains[tapset0][1]); int b3 = Inlines.MULT16_16_P15(g0, gains[tapset0][2]); int num = Inlines.MULT16_16_P15(g1, gains[tapset1][0]); int num2 = Inlines.MULT16_16_P15(g1, gains[tapset1][1]); int num3 = Inlines.MULT16_16_P15(g1, gains[tapset1][2]); int num4 = x[x_ptr - T1 + 1]; int num5 = x[x_ptr - T1]; int num6 = x[x_ptr - T1 - 1]; int b4 = x[x_ptr - T1 - 2]; if (g0 == g1 && T0 == T1 && tapset0 == tapset1) { overlap = 0; } int i; for (i = 0; i < overlap; i++) { int num7 = x[x_ptr + i - T1 + 2]; int num8 = Inlines.MULT16_16_Q15(window[i], window[i]); y[y_ptr + i] = x[x_ptr + i] + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15((short)(32767 - num8), b), x[x_ptr + i - T0]) + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15((short)(32767 - num8), b2), Inlines.ADD32(x[x_ptr + i - T0 + 1], x[x_ptr + i - T0 - 1])) + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15((short)(32767 - num8), b3), Inlines.ADD32(x[x_ptr + i - T0 + 2], x[x_ptr + i - T0 - 2])) + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15(num8, num), num5) + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15(num8, num2), Inlines.ADD32(num4, num6)) + Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15(num8, num3), Inlines.ADD32(num7, b4)); b4 = num6; num6 = num5; num5 = num4; num4 = num7; } if (g1 != 0) { comb_filter_const(y, y_ptr + i, x, x_ptr + i, T1, N - i, num, num2, num3); } } } internal static void init_caps(CeltMode m, int[] cap, int LM, int C) { for (int i = 0; i < m.nbEBands; i++) { int num = m.eBands[i + 1] - m.eBands[i] << LM; cap[i] = (m.cache.caps[m.nbEBands * (2 * LM + C - 1) + i] + 64) * C * num >> 2; } } } internal static class CeltConstants { internal const int Q15ONE = 32767; internal const float CELT_SIG_SCALE = 32768f; internal const int SIG_SHIFT = 12; internal const int NORM_SCALING = 16384; internal const int DB_SHIFT = 10; internal const int EPSILON = 1; internal const int VERY_SMALL = 0; internal const short VERY_LARGE16 = short.MaxValue; internal const short Q15_ONE = short.MaxValue; internal const int COMBFILTER_MAXPERIOD = 1024; internal const int COMBFILTER_MINPERIOD = 15; internal const int DECODE_BUFFER_SIZE = 2048; internal const int BITALLOC_SIZE = 11; internal const int MAX_PERIOD = 1024; internal const int TOTAL_MODES = 1; internal const int MAX_PSEUDO = 40; internal const int LOG_MAX_PSEUDO = 6; internal const int CELT_MAX_PULSES = 128; internal const int MAX_FINE_BITS = 8; internal const int FINE_OFFSET = 21; internal const int QTHETA_OFFSET = 4; internal const int QTHETA_OFFSET_TWOPHASE = 16; internal const int PLC_PITCH_LAG_MAX = 720; internal const int PLC_PITCH_LAG_MIN = 100; internal const int LPC_ORDER = 24; } internal static class CeltLPC { private const int LPC_ORDER = 24; internal static void celt_lpc(int[] _lpc, int[] ac, int p) { int num = ac[0]; Span span = stackalloc int[24]; if (ac[0] != 0) { for (int i = 0; i < p; i++) { int num2 = 0; for (int j = 0; j < i; j++) { num2 += Inlines.MULT32_32_Q31(span[j], ac[i - j]); } num2 += Inlines.SHR32(ac[i + 1], 3); int num3 = -Inlines.frac_div32(Inlines.SHL32(num2, 3), num); span[i] = Inlines.SHR32(num3, 3); for (int j = 0; j < i + 1 >> 1; j++) { int num4 = span[j]; int num5 = span[i - 1 - j]; span[j] = num4 + Inlines.MULT32_32_Q31(num3, num5); span[i - 1 - j] = num5 + Inlines.MULT32_32_Q31(num3, num4); } num -= Inlines.MULT32_32_Q31(Inlines.MULT32_32_Q31(num3, num3), num); if (num < Inlines.SHR32(ac[0], 10)) { break; } } } for (int i = 0; i < p; i++) { _lpc[i] = Inlines.ROUND16(span[i], 16); } } internal static void celt_iir(Span _x, int[] den, Span _y, int N, int ord, Span mem) { int[] array = new int[ord]; int[] array2 = new int[N + ord]; int i; for (i = 0; i < ord; i++) { array[i] = den[ord - i - 1]; } for (i = 0; i < ord; i++) { array2[i] = -mem[ord - i - 1]; } for (; i < N + ord; i++) { array2[i] = 0; } for (i = 0; i < N - 3; i += 4) { int sum = _x[i]; int sum2 = _x[i + 1]; int sum3 = _x[i + 2]; int sum4 = _x[i + 3]; Kernels.xcorr_kernel(array, 0, array2, i, ref sum, ref sum2, ref sum3, ref sum4, ord); array2[i + ord] = -Inlines.ROUND16(sum, 12); _y[i] = sum; sum2 = Inlines.MAC16_16(sum2, array2[i + ord], den[0]); array2[i + ord + 1] = -Inlines.ROUND16(sum2, 12); _y[i + 1] = sum2; sum3 = Inlines.MAC16_16(sum3, array2[i + ord + 1], den[0]); sum3 = Inlines.MAC16_16(sum3, array2[i + ord], den[1]); array2[i + ord + 2] = -Inlines.ROUND16(sum3, 12); _y[i + 2] = sum3; sum4 = Inlines.MAC16_16(sum4, array2[i + ord + 2], den[0]); sum4 = Inlines.MAC16_16(sum4, array2[i + ord + 1], den[1]); sum4 = Inlines.MAC16_16(sum4, array2[i + ord], den[2]); array2[i + ord + 3] = -Inlines.ROUND16(sum4, 12); _y[i + 3] = sum4; } for (; i < N; i++) { int num = _x[i]; for (int j = 0; j < ord; j++) { num -= Inlines.MULT16_16(array[j], array2[i + j]); } array2[i + ord] = Inlines.ROUND16(num, 12); _y[i] = num; } for (i = 0; i < ord; i++) { mem[i] = _y[N - i - 1]; } } } internal static class CeltPitchXCorr { internal static int pitch_xcorr(int[] _x, int x_idx, int[] _y, int y_idx, Span xcorr, int len, int max_pitch) { int num = 1; int i; if (Vector.IsHardwareAccelerated) { for (i = 0; i < max_pitch - 3; i += 4) { int sum = 0; int sum2 = 0; int sum3 = 0; int sum4 = 0; Kernels.xcorr_kernel_vector(_x, x_idx, _y, y_idx + i, ref sum, ref sum2, ref sum3, ref sum4, len); xcorr[i] = sum; xcorr[i + 1] = sum2; xcorr[i + 2] = sum3; xcorr[i + 3] = sum4; sum = Inlines.MAX32(sum, sum2); sum3 = Inlines.MAX32(sum3, sum4); sum = Inlines.MAX32(sum, sum3); num = Inlines.MAX32(num, sum); } } else { for (i = 0; i < max_pitch - 3; i += 4) { int sum5 = 0; int sum6 = 0; int sum7 = 0; int sum8 = 0; Kernels.xcorr_kernel(_x, x_idx, _y, y_idx + i, ref sum5, ref sum6, ref sum7, ref sum8, len); xcorr[i] = sum5; xcorr[i + 1] = sum6; xcorr[i + 2] = sum7; xcorr[i + 3] = sum8; sum5 = Inlines.MAX32(sum5, sum6); sum7 = Inlines.MAX32(sum7, sum8); sum5 = Inlines.MAX32(sum5, sum7); num = Inlines.MAX32(num, sum5); } } for (; i < max_pitch; i++) { int num2 = Kernels.celt_inner_prod(_x.AsSpan(), _y.AsSpan(i), len); xcorr[i] = num2; num = Inlines.MAX32(num, num2); } return num; } internal static int pitch_xcorr(short[] _x, int x_idx, short[] _y, int y_idx, int[] xcorr, int len, int max_pitch) { int num = 1; int i; for (i = 0; i < max_pitch - 3; i += 4) { int sum = 0; int sum2 = 0; int sum3 = 0; int sum4 = 0; Kernels.xcorr_kernel(_x, x_idx, _y, y_idx + i, ref sum, ref sum2, ref sum3, ref sum4, len); xcorr[i] = sum; xcorr[i + 1] = sum2; xcorr[i + 2] = sum3; xcorr[i + 3] = sum4; sum = Inlines.MAX32(sum, sum2); sum3 = Inlines.MAX32(sum3, sum4); sum = Inlines.MAX32(sum, sum3); num = Inlines.MAX32(num, sum); } for (; i < max_pitch; i++) { num = Inlines.MAX32(num, xcorr[i] = Kernels.celt_inner_prod(_x.AsSpan(x_idx), _y.AsSpan(y_idx + i), len)); } return num; } } internal static class CWRS { internal static readonly uint[] CELT_PVQ_U_ROW = new uint[15] { 0u, 176u, 351u, 525u, 698u, 870u, 1041u, 1131u, 1178u, 1207u, 1226u, 1240u, 1248u, 1254u, 1257u }; private static uint CELT_PVQ_U(int _n, int _k) { return Tables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[Inlines.IMIN(_n, _k)] + Inlines.IMAX(_n, _k)]; } private static uint CELT_PVQ_V(int _n, int _k) { return CELT_PVQ_U(_n, _k) + CELT_PVQ_U(_n, _k + 1); } internal static uint icwrs(int _n, int[] _y) { int num = _n - 1; uint num2 = ((_y[num] < 0) ? 1u : 0u); int num3 = Inlines.abs(_y[num]); do { num--; num2 += CELT_PVQ_U(_n - num, num3); num3 += Inlines.abs(_y[num]); if (_y[num] < 0) { num2 += CELT_PVQ_U(_n - num, num3 + 1); } } while (num > 0); return num2; } internal static void encode_pulses(int[] _y, int _n, int _k, EntropyCoder _enc, Span encodedData) { _enc.enc_uint(encodedData, icwrs(_n, _y), CELT_PVQ_V(_n, _k)); } internal static int cwrsi(int _n, int _k, uint _i, int[] _y) { int c = 0; int num = 0; uint num3; int num5; int num4; short num7; while (_n > 2) { if (_k >= _n) { uint num2 = CELT_PVQ_U_ROW[_n]; num3 = Tables.CELT_PVQ_U_DATA[num2 + _k + 1]; num4 = 0 - ((_i >= num3) ? 1 : 0); _i -= num3 & (uint)num4; num5 = _k; uint num6 = Tables.CELT_PVQ_U_DATA[num2 + _n]; if (num6 > _i) { _k = _n; do { num3 = Tables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[--_k] + _n]; } while (num3 > _i); } else { for (num3 = Tables.CELT_PVQ_U_DATA[num2 + _k]; num3 > _i; num3 = Tables.CELT_PVQ_U_DATA[num2 + _k]) { _k--; } } _i -= num3; num7 = (short)((num5 - _k + num4) ^ num4); _y[num++] = num7; c = Inlines.MAC16_16(c, num7, num7); } else { num3 = Tables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[_k] + _n]; uint num6 = Tables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[_k + 1] + _n]; if (num3 <= _i && _i < num6) { _i -= num3; _y[num++] = 0; } else { num4 = 0 - ((_i >= num6) ? 1 : 0); _i -= num6 & (uint)num4; num5 = _k; do { num3 = Tables.CELT_PVQ_U_DATA[CELT_PVQ_U_ROW[--_k] + _n]; } while (num3 > _i); _i -= num3; num7 = (short)((num5 - _k + num4) ^ num4); _y[num++] = num7; c = Inlines.MAC16_16(c, num7, num7); } } _n--; } num3 = (uint)(2 * _k + 1); num4 = 0 - ((_i >= num3) ? 1 : 0); _i -= num3 & (uint)num4; num5 = _k; _k = (int)(_i + 1 >> 1); if (_k != 0) { _i -= (uint)(2 * _k - 1); } num7 = (short)((num5 - _k + num4) ^ num4); _y[num++] = num7; c = Inlines.MAC16_16(c, num7, num7); num4 = (int)(0 - _i); num7 = (short)(_y[num] = (short)((_k + num4) ^ num4)); return Inlines.MAC16_16(c, num7, num7); } internal static int decode_pulses(int[] _y, int _n, int _k, EntropyCoder _dec, ReadOnlySpan encodedData) { return cwrsi(_n, _k, _dec.dec_uint(encodedData, CELT_PVQ_V(_n, _k)), _y); } } internal static class Kernels { internal static void celt_fir(Span x, Span num, Span y, int N, int ord, Span mem) { short[] array = new short[ord]; short[] array2 = new short[N + ord]; int i; for (i = 0; i < ord; i++) { array[i] = num[ord - i - 1]; } for (i = 0; i < ord; i++) { array2[i] = mem[ord - i - 1]; } for (i = 0; i < N; i++) { array2[i + ord] = x[i]; } for (i = 0; i < ord; i++) { mem[i] = x[N - i - 1]; } for (i = 0; i < N - 3; i += 4) { int sum = 0; int sum2 = 0; int sum3 = 0; int sum4 = 0; xcorr_kernel(array, 0, array2, i, ref sum, ref sum2, ref sum3, ref sum4, ord); y[i] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[i]), Inlines.PSHR32(sum, 12))); y[i + 1] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[i + 1]), Inlines.PSHR32(sum2, 12))); y[i + 2] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[i + 2]), Inlines.PSHR32(sum3, 12))); y[i + 3] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[i + 3]), Inlines.PSHR32(sum4, 12))); } for (; i < N; i++) { int num2 = 0; for (int j = 0; j < ord; j++) { num2 = Inlines.MAC16_16(num2, array[j], array2[i + j]); } y[i] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[i]), Inlines.PSHR32(num2, 12))); } } internal static void celt_fir(Span x, Span num, Span y, int N, int ord, Span mem) { int[] array = new int[ord]; int[] array2 = new int[N + ord]; int i; for (i = 0; i < ord; i++) { array[i] = num[ord - i - 1]; } for (i = 0; i < ord; i++) { array2[i] = mem[ord - i - 1]; } for (i = 0; i < N; i++) { array2[i + ord] = x[i]; } for (i = 0; i < ord; i++) { mem[i] = x[N - i - 1]; } for (i = 0; i < N - 3; i += 4) { int sum = 0; int sum2 = 0; int sum3 = 0; int sum4 = 0; xcorr_kernel(array, 0, array2, i, ref sum, ref sum2, ref sum3, ref sum4, ord); y[i] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[i]), Inlines.PSHR32(sum, 12))); y[i + 1] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[i + 1]), Inlines.PSHR32(sum2, 12))); y[i + 2] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[i + 2]), Inlines.PSHR32(sum3, 12))); y[i + 3] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[i + 3]), Inlines.PSHR32(sum4, 12))); } for (; i < N; i++) { int num2 = 0; for (int j = 0; j < ord; j++) { num2 = Inlines.MAC16_16(num2, array[j], array2[i + j]); } y[i] = Inlines.SATURATE16(Inlines.ADD32(Inlines.EXTEND32(x[i]), Inlines.PSHR32(num2, 12))); } } internal static void xcorr_kernel(short[] x, int x_idx, short[] y, int y_idx, ref int sum0, ref int sum1, ref int sum2, ref int sum3, int len) { int num = x_idx; int num2 = y_idx; short b = 0; short b2 = y[num2++]; short b3 = y[num2++]; short b4 = y[num2++]; int i; for (i = 0; i < len - 3; i += 4) { short a = x[num++]; b = y[num2++]; sum0 = Inlines.MAC16_16(sum0, a, b2); sum1 = Inlines.MAC16_16(sum1, a, b3); sum2 = Inlines.MAC16_16(sum2, a, b4); sum3 = Inlines.MAC16_16(sum3, a, b); a = x[num++]; b2 = y[num2++]; sum0 = Inlines.MAC16_16(sum0, a, b3); sum1 = Inlines.MAC16_16(sum1, a, b4); sum2 = Inlines.MAC16_16(sum2, a, b); sum3 = Inlines.MAC16_16(sum3, a, b2); a = x[num++]; b3 = y[num2++]; sum0 = Inlines.MAC16_16(sum0, a, b4); sum1 = Inlines.MAC16_16(sum1, a, b); sum2 = Inlines.MAC16_16(sum2, a, b2); sum3 = Inlines.MAC16_16(sum3, a, b3); a = x[num++]; b4 = y[num2++]; sum0 = Inlines.MAC16_16(sum0, a, b); sum1 = Inlines.MAC16_16(sum1, a, b2); sum2 = Inlines.MAC16_16(sum2, a, b3); sum3 = Inlines.MAC16_16(sum3, a, b4); } if (i++ < len) { short a2 = x[num++]; b = y[num2++]; sum0 = Inlines.MAC16_16(sum0, a2, b2); sum1 = Inlines.MAC16_16(sum1, a2, b3); sum2 = Inlines.MAC16_16(sum2, a2, b4); sum3 = Inlines.MAC16_16(sum3, a2, b); } if (i++ < len) { short a3 = x[num++]; b2 = y[num2++]; sum0 = Inlines.MAC16_16(sum0, a3, b3); sum1 = Inlines.MAC16_16(sum1, a3, b4); sum2 = Inlines.MAC16_16(sum2, a3, b); sum3 = Inlines.MAC16_16(sum3, a3, b2); } if (i < len) { short a4 = x[num++]; b3 = y[num2++]; sum0 = Inlines.MAC16_16(sum0, a4, b4); sum1 = Inlines.MAC16_16(sum1, a4, b); sum2 = Inlines.MAC16_16(sum2, a4, b2); sum3 = Inlines.MAC16_16(sum3, a4, b3); } } internal static void xcorr_kernel(int[] x, int x_idx, int[] y, int y_idx, ref int sum0, ref int sum1, ref int sum2, ref int sum3, int len) { int num = x_idx; int num2 = y_idx; int b = 0; int b2 = y[num2++]; int b3 = y[num2++]; int b4 = y[num2++]; int i; for (i = 0; i < len - 3; i += 4) { int a = x[num++]; b = y[num2++]; sum0 = Inlines.MAC16_16(sum0, a, b2); sum1 = Inlines.MAC16_16(sum1, a, b3); sum2 = Inlines.MAC16_16(sum2, a, b4); sum3 = Inlines.MAC16_16(sum3, a, b); a = x[num++]; b2 = y[num2++]; sum0 = Inlines.MAC16_16(sum0, a, b3); sum1 = Inlines.MAC16_16(sum1, a, b4); sum2 = Inlines.MAC16_16(sum2, a, b); sum3 = Inlines.MAC16_16(sum3, a, b2); a = x[num++]; b3 = y[num2++]; sum0 = Inlines.MAC16_16(sum0, a, b4); sum1 = Inlines.MAC16_16(sum1, a, b); sum2 = Inlines.MAC16_16(sum2, a, b2); sum3 = Inlines.MAC16_16(sum3, a, b3); a = x[num++]; b4 = y[num2++]; sum0 = Inlines.MAC16_16(sum0, a, b); sum1 = Inlines.MAC16_16(sum1, a, b2); sum2 = Inlines.MAC16_16(sum2, a, b3); sum3 = Inlines.MAC16_16(sum3, a, b4); } if (i++ < len) { int a2 = x[num++]; b = y[num2++]; sum0 = Inlines.MAC16_16(sum0, a2, b2); sum1 = Inlines.MAC16_16(sum1, a2, b3); sum2 = Inlines.MAC16_16(sum2, a2, b4); sum3 = Inlines.MAC16_16(sum3, a2, b); } if (i++ < len) { int a3 = x[num++]; b2 = y[num2++]; sum0 = Inlines.MAC16_16(sum0, a3, b3); sum1 = Inlines.MAC16_16(sum1, a3, b4); sum2 = Inlines.MAC16_16(sum2, a3, b); sum3 = Inlines.MAC16_16(sum3, a3, b2); } if (i < len) { int a4 = x[num++]; b3 = y[num2++]; sum0 = Inlines.MAC16_16(sum0, a4, b4); sum1 = Inlines.MAC16_16(sum1, a4, b); sum2 = Inlines.MAC16_16(sum2, a4, b2); sum3 = Inlines.MAC16_16(sum3, a4, b3); } } internal static void xcorr_kernel_vector(int[] x, int x_idx, int[] y, int y_idx, ref int sum0, ref int sum1, ref int sum2, ref int sum3, int len) { int i = 0; for (int num = len - 4 - (len - 4) % Vector.Count; i < num; i += Vector.Count) { Vector left = new Vector(x, x_idx + i); sum0 += Vector.Dot(Vector.One, Vector.Multiply(left, new Vector(y, y_idx + i))); sum1 += Vector.Dot(Vector.One, Vector.Multiply(left, new Vector(y, y_idx + i + 1))); sum2 += Vector.Dot(Vector.One, Vector.Multiply(left, new Vector(y, y_idx + i + 2))); sum3 += Vector.Dot(Vector.One, Vector.Multiply(left, new Vector(y, y_idx + i + 3))); } for (; i < len; i++) { int a = x[x_idx + i]; sum0 = Inlines.MAC16_16(sum0, a, y[y_idx + i]); sum1 = Inlines.MAC16_16(sum1, a, y[y_idx + i + 1]); sum2 = Inlines.MAC16_16(sum2, a, y[y_idx + i + 2]); sum3 = Inlines.MAC16_16(sum3, a, y[y_idx + i + 3]); } } internal static int celt_inner_prod(Span x, Span y, int N) { int num = 0; for (int i = 0; i < N; i++) { num = Inlines.MAC16_16(num, x[i], y[i]); } return num; } internal static int celt_inner_prod(Span x, Span y, int N) { int num = 0; for (int i = 0; i < N; i++) { num = Inlines.MAC16_16(num, x[i], y[i]); } return num; } internal static void dual_inner_prod(Span x, Span y01, Span y02, int N, out int xy1, out int xy2) { int num = 0; int num2 = 0; for (int i = 0; i < N; i++) { num = Inlines.MAC16_16(num, x[i], y01[i]); num2 = Inlines.MAC16_16(num2, x[i], y02[i]); } xy1 = num; xy2 = num2; } } internal static class KissFFT { internal const int MAXFACTORS = 8; internal static int S_MUL(int a, int b) { return Inlines.MULT16_32_Q15(b, a); } internal static int S_MUL(int a, short b) { return Inlines.MULT16_32_Q15(b, a); } internal static int HALF_OF(int x) { return x >> 1; } internal static void kf_bfly2(Span Fout, int fout_ptr, int m, int N) { short b = 23170; for (int i = 0; i < N; i++) { int num = fout_ptr + 8; int num2 = Fout[num]; int num3 = Fout[num + 1]; Fout[num] = Fout[fout_ptr] - num2; Fout[num + 1] = Fout[fout_ptr + 1] - num3; Fout[fout_ptr] += num2; Fout[fout_ptr + 1] += num3; num2 = S_MUL(Fout[num + 2] + Fout[num + 3], b); num3 = S_MUL(Fout[num + 3] - Fout[num + 2], b); Fout[num + 2] = Fout[fout_ptr + 2] - num2; Fout[num + 3] = Fout[fout_ptr + 3] - num3; Fout[fout_ptr + 2] += num2; Fout[fout_ptr + 3] += num3; num2 = Fout[num + 5]; num3 = -Fout[num + 4]; Fout[num + 4] = Fout[fout_ptr + 4] - num2; Fout[num + 5] = Fout[fout_ptr + 5] - num3; Fout[fout_ptr + 4] += num2; Fout[fout_ptr + 5] += num3; num2 = S_MUL(Fout[num + 7] - Fout[num + 6], b); num3 = S_MUL(-Fout[num + 7] - Fout[num + 6], b); Fout[num + 6] = Fout[fout_ptr + 6] - num2; Fout[num + 7] = Fout[fout_ptr + 7] - num3; Fout[fout_ptr + 6] += num2; Fout[fout_ptr + 7] += num3; fout_ptr += 16; } } internal static void kf_bfly4(Span Fout, int fout_ptr, int fstride, FFTState st, int m, int N, int mm) { if (m == 1) { for (int i = 0; i < N; i++) { int num = Fout[fout_ptr] - Fout[fout_ptr + 4]; int num2 = Fout[fout_ptr + 1] - Fout[fout_ptr + 5]; Fout[fout_ptr] += Fout[fout_ptr + 4]; Fout[fout_ptr + 1] += Fout[fout_ptr + 5]; int num3 = Fout[fout_ptr + 2] + Fout[fout_ptr + 6]; int num4 = Fout[fout_ptr + 3] + Fout[fout_ptr + 7]; Fout[fout_ptr + 4] = Fout[fout_ptr] - num3; Fout[fout_ptr + 5] = Fout[fout_ptr + 1] - num4; Fout[fout_ptr] += num3; Fout[fout_ptr + 1] += num4; num3 = Fout[fout_ptr + 2] - Fout[fout_ptr + 6]; num4 = Fout[fout_ptr + 3] - Fout[fout_ptr + 7]; Fout[fout_ptr + 2] = num + num4; Fout[fout_ptr + 3] = num2 - num3; Fout[fout_ptr + 6] = num - num4; Fout[fout_ptr + 7] = num2 + num3; fout_ptr += 8; } return; } int num5 = fout_ptr; for (int i = 0; i < N; i++) { fout_ptr = num5 + 2 * i * mm; int num6 = fout_ptr + 2 * m; int num7 = fout_ptr + 4 * m; int num8 = fout_ptr + 6 * m; int num10; int num9; int num11 = (num10 = (num9 = 0)); for (int j = 0; j < m; j++) { int num12 = S_MUL(Fout[num6], st.twiddles[num9]) - S_MUL(Fout[num6 + 1], st.twiddles[num9 + 1]); int num13 = S_MUL(Fout[num6], st.twiddles[num9 + 1]) + S_MUL(Fout[num6 + 1], st.twiddles[num9]); int num14 = S_MUL(Fout[num7], st.twiddles[num10]) - S_MUL(Fout[num7 + 1], st.twiddles[num10 + 1]); int num15 = S_MUL(Fout[num7], st.twiddles[num10 + 1]) + S_MUL(Fout[num7 + 1], st.twiddles[num10]); int num16 = S_MUL(Fout[num8], st.twiddles[num11]) - S_MUL(Fout[num8 + 1], st.twiddles[num11 + 1]); int num17 = S_MUL(Fout[num8], st.twiddles[num11 + 1]) + S_MUL(Fout[num8 + 1], st.twiddles[num11]); int num18 = Fout[fout_ptr] - num14; int num19 = Fout[fout_ptr + 1] - num15; Fout[fout_ptr] += num14; Fout[fout_ptr + 1] += num15; int num20 = num12 + num16; int num21 = num13 + num17; int num22 = num12 - num16; int num23 = num13 - num17; Fout[num7] = Fout[fout_ptr] - num20; Fout[num7 + 1] = Fout[fout_ptr + 1] - num21; num9 += fstride * 2; num10 += fstride * 4; num11 += fstride * 6; Fout[fout_ptr] += num20; Fout[fout_ptr + 1] += num21; Fout[num6] = num18 + num23; Fout[num6 + 1] = num19 - num22; Fout[num8] = num18 - num23; Fout[num8 + 1] = num19 + num22; fout_ptr += 2; num6 += 2; num7 += 2; num8 += 2; } } } internal static void kf_bfly3(Span Fout, int fout_ptr, int fstride, FFTState st, int m, int N, int mm) { int num = 2 * m; int num2 = 4 * m; int num3 = fout_ptr; for (int i = 0; i < N; i++) { fout_ptr = num3 + 2 * i * mm; int num4; int num5 = (num4 = 0); int num6 = m; do { int num7 = S_MUL(Fout[fout_ptr + num], st.twiddles[num5]) - S_MUL(Fout[fout_ptr + num + 1], st.twiddles[num5 + 1]); int num8 = S_MUL(Fout[fout_ptr + num], st.twiddles[num5 + 1]) + S_MUL(Fout[fout_ptr + num + 1], st.twiddles[num5]); int num9 = S_MUL(Fout[fout_ptr + num2], st.twiddles[num4]) - S_MUL(Fout[fout_ptr + num2 + 1], st.twiddles[num4 + 1]); int num10 = S_MUL(Fout[fout_ptr + num2], st.twiddles[num4 + 1]) + S_MUL(Fout[fout_ptr + num2 + 1], st.twiddles[num4]); int num11 = num7 + num9; int num12 = num8 + num10; int a = num7 - num9; int a2 = num8 - num10; num5 += fstride * 2; num4 += fstride * 4; Fout[fout_ptr + num] = Fout[fout_ptr] - HALF_OF(num11); Fout[fout_ptr + num + 1] = Fout[fout_ptr + 1] - HALF_OF(num12); a = S_MUL(a, -28378); a2 = S_MUL(a2, -28378); Fout[fout_ptr] += num11; Fout[fout_ptr + 1] += num12; Fout[fout_ptr + num2] = Fout[fout_ptr + num] + a2; Fout[fout_ptr + num2 + 1] = Fout[fout_ptr + num + 1] - a; Fout[fout_ptr + num] -= a2; Fout[fout_ptr + num + 1] += a; fout_ptr += 2; } while (--num6 != 0); } } internal static void kf_bfly5(Span Fout, int fout_ptr, int fstride, FFTState st, int m, int N, int mm) { int num = fout_ptr; short b = 10126; short b2 = -31164; short b3 = -26510; short b4 = -19261; for (int i = 0; i < N; i++) { int num4; int num3; int num2; int num5 = (num4 = (num3 = (num2 = 0))); fout_ptr = num + 2 * i * mm; int num6 = fout_ptr; int num7 = fout_ptr + 2 * m; int num8 = fout_ptr + 4 * m; int num9 = fout_ptr + 6 * m; int num10 = fout_ptr + 8 * m; for (int j = 0; j < m; j++) { int num11 = Fout[num6]; int num12 = Fout[num6 + 1]; int num13 = S_MUL(Fout[num7], st.twiddles[num5]) - S_MUL(Fout[num7 + 1], st.twiddles[num5 + 1]); int num14 = S_MUL(Fout[num7], st.twiddles[num5 + 1]) + S_MUL(Fout[num7 + 1], st.twiddles[num5]); int num15 = S_MUL(Fout[num8], st.twiddles[num4]) - S_MUL(Fout[num8 + 1], st.twiddles[num4 + 1]); int num16 = S_MUL(Fout[num8], st.twiddles[num4 + 1]) + S_MUL(Fout[num8 + 1], st.twiddles[num4]); int num17 = S_MUL(Fout[num9], st.twiddles[num3]) - S_MUL(Fout[num9 + 1], st.twiddles[num3 + 1]); int num18 = S_MUL(Fout[num9], st.twiddles[num3 + 1]) + S_MUL(Fout[num9 + 1], st.twiddles[num3]); int num19 = S_MUL(Fout[num10], st.twiddles[num2]) - S_MUL(Fout[num10 + 1], st.twiddles[num2 + 1]); int num20 = S_MUL(Fout[num10], st.twiddles[num2 + 1]) + S_MUL(Fout[num10 + 1], st.twiddles[num2]); num5 += 2 * fstride; num4 += 4 * fstride; num3 += 6 * fstride; num2 += 8 * fstride; int num21 = num13 + num19; int num22 = num14 + num20; int a = num13 - num19; int a2 = num14 - num20; int num23 = num15 + num17; int num24 = num16 + num18; int a3 = num15 - num17; int a4 = num16 - num18; Fout[num6] += num21 + num23; Fout[num6 + 1] += num22 + num24; int num25 = num11 + S_MUL(num21, b) + S_MUL(num23, b3); int num26 = num12 + S_MUL(num22, b) + S_MUL(num24, b3); int num27 = S_MUL(a2, b2) + S_MUL(a4, b4); int num28 = -S_MUL(a, b2) - S_MUL(a3, b4); Fout[num7] = num25 - num27; Fout[num7 + 1] = num26 - num28; Fout[num10] = num25 + num27; Fout[num10 + 1] = num26 + num28; int num29 = num11 + S_MUL(num21, b3) + S_MUL(num23, b); int num30 = num12 + S_MUL(num22, b3) + S_MUL(num24, b); int num31 = -S_MUL(a2, b4) + S_MUL(a4, b2); int num32 = S_MUL(a, b4) - S_MUL(a3, b2); Fout[num8] = num29 + num31; Fout[num8 + 1] = num30 + num32; Fout[num9] = num29 - num31; Fout[num9 + 1] = num30 - num32; num6 += 2; num7 += 2; num8 += 2; num9 += 2; num10 += 2; } } } internal static void opus_fft_impl(FFTState st, Span fout, int fout_ptr) { int[] array = new int[8]; int num = ((st.shift > 0) ? st.shift : 0); array[0] = 1; int num2 = 0; int num4; do { int num3 = st.factors[2 * num2]; num4 = st.factors[2 * num2 + 1]; array[num2 + 1] = array[num2] * num3; num2++; } while (num4 != 1); num4 = st.factors[2 * num2 - 1]; for (int num5 = num2 - 1; num5 >= 0; num5--) { int num6 = ((num5 == 0) ? 1 : st.factors[2 * num5 - 1]); switch (st.factors[2 * num5]) { case 2: kf_bfly2(fout, fout_ptr, num4, array[num5]); break; case 4: kf_bfly4(fout, fout_ptr, array[num5] << num, st, num4, array[num5], num6); break; case 3: kf_bfly3(fout, fout_ptr, array[num5] << num, st, num4, array[num5], num6); break; case 5: kf_bfly5(fout, fout_ptr, array[num5] << num, st, num4, array[num5], num6); break; } num4 = num6; } } internal static void opus_fft(FFTState st, int[] fin, int[] fout) { int shift = st.scale_shift - 1; short scale = st.scale; for (int i = 0; i < st.nfft; i++) { fout[2 * st.bitrev[i]] = Inlines.SHR32(Inlines.MULT16_32_Q16(scale, fin[2 * i]), shift); fout[2 * st.bitrev[i] + 1] = Inlines.SHR32(Inlines.MULT16_32_Q16(scale, fin[2 * i + 1]), shift); } opus_fft_impl(st, fout, 0); } } internal static class Laplace { private const int LAPLACE_LOG_MINP = 0; private const uint LAPLACE_MINP = 1u; private const int LAPLACE_NMIN = 16; internal static uint ec_laplace_get_freq1(uint fs0, int decay) { return (uint)((32736 - fs0) * (16384 - decay) >> 15); } internal static void ec_laplace_encode(EntropyCoder enc, Span encodedData, ref int value, uint fs, int decay) { int num = value; uint num2 = 0u; if (num != 0) { int num3 = 0 - ((num < 0) ? 1 : 0); num = (num + num3) ^ num3; num2 = fs; fs = ec_laplace_get_freq1(fs, decay); int num4 = 1; while (fs != 0 && num4 < num) { fs *= 2; num2 += fs + 2; fs = (uint)(fs * decay >> 15); num4++; } if (fs == 0) { int num5 = (int)(32768 - num2 + 1 - 1); num5 = num5 - num3 >> 1; int num6 = Inlines.IMIN(num - num4, num5 - 1); num2 += (uint)(2 * num6 + 1 + num3); fs = Inlines.IMIN(1u, 32768 - num2); value = (num4 + num6 + num3) ^ num3; } else { fs++; num2 += (uint)(int)(fs & ~num3); } } enc.encode_bin(encodedData, num2, num2 + fs, 15u); } internal static int ec_laplace_decode(EntropyCoder dec, ReadOnlySpan encodedData, uint fs, int decay) { int num = 0; uint num2 = dec.decode_bin(15u); uint num3 = 0u; if (num2 >= fs) { num++; num3 = fs; fs = ec_laplace_get_freq1(fs, decay) + 1; while (fs > 1 && num2 >= num3 + 2 * fs) { fs *= 2; num3 += fs; fs = (uint)((fs - 2) * decay >> 15); fs++; num++; } if (fs <= 1) { int num4 = (int)(num2 - num3) >> 1; num += num4; num3 += (uint)(2 * num4); } if (num2 < num3 + fs) { num = -num; } else { num3 += fs; } } dec.dec_update(encodedData, num3, Inlines.IMIN(num3 + fs, 32768u), 32768u); return num; } } internal static class MDCT { internal static void clt_mdct_forward(MDCTLookup l, Span input, int input_ptr, Span output, int output_ptr, int[] window, int overlap, int shift, int stride) { FFTState fFTState = l.kfft[shift]; int num = 0; int shift2 = fFTState.scale_shift - 1; int scale = fFTState.scale; int num2 = l.n; short[] trig = l.trig; int i; for (i = 0; i < shift; i++) { num2 >>= 1; num += num2; } int num3 = num2 >> 1; int num4 = num2 >> 2; int[] array = new int[num3]; int[] array2 = new int[num4 * 2]; int num5 = input_ptr + (overlap >> 1); int num6 = input_ptr + num3 - 1 + (overlap >> 1); int num7 = 0; int num8 = overlap >> 1; int num9 = (overlap >> 1) - 1; for (i = 0; i < overlap + 3 >> 2; i++) { array[num7++] = Inlines.MULT16_32_Q15(window[num9], input[num5 + num3]) + Inlines.MULT16_32_Q15(window[num8], input[num6]); array[num7++] = Inlines.MULT16_32_Q15(window[num8], input[num5]) - Inlines.MULT16_32_Q15(window[num9], input[num6 - num3]); num5 += 2; num6 -= 2; num8 += 2; num9 -= 2; } num8 = 0; num9 = overlap - 1; for (; i < num4 - (overlap + 3 >> 2); i++) { array[num7++] = input[num6]; array[num7++] = input[num5]; num5 += 2; num6 -= 2; } for (; i < num4; i++) { array[num7++] = Inlines.MULT16_32_Q15(window[num9], input[num6]) - Inlines.MULT16_32_Q15(window[num8], input[num5 - num3]); array[num7++] = Inlines.MULT16_32_Q15(window[num9], input[num5]) + Inlines.MULT16_32_Q15(window[num8], input[num6 + num3]); num5 += 2; num6 -= 2; num8 += 2; num9 -= 2; } int num10 = 0; int num11 = num; for (i = 0; i < num4; i++) { short b = trig[num11 + i]; short b2 = trig[num11 + num4 + i]; int a = array[num10++]; int a2 = array[num10++]; int b3 = KissFFT.S_MUL(a, b) - KissFFT.S_MUL(a2, b2); int b4 = KissFFT.S_MUL(a2, b) + KissFFT.S_MUL(a, b2); array2[2 * fFTState.bitrev[i]] = Inlines.PSHR32(Inlines.MULT16_32_Q16(scale, b3), shift2); array2[2 * fFTState.bitrev[i] + 1] = Inlines.PSHR32(Inlines.MULT16_32_Q16(scale, b4), shift2); } KissFFT.opus_fft_impl(fFTState, array2, 0); int num12 = 0; int num13 = output_ptr; int num14 = output_ptr + stride * (num3 - 1); int num15 = num; for (i = 0; i < num4; i++) { int num16 = KissFFT.S_MUL(array2[num12 + 1], trig[num15 + num4 + i]) - KissFFT.S_MUL(array2[num12], trig[num15 + i]); int num17 = KissFFT.S_MUL(array2[num12], trig[num15 + num4 + i]) + KissFFT.S_MUL(array2[num12 + 1], trig[num15 + i]); output[num13] = num16; output[num14] = num17; num12 += 2; num13 += 2 * stride; num14 -= 2 * stride; } } internal static void clt_mdct_backward(MDCTLookup l, Span input, int input_ptr, Span output, int output_ptr, int[] window, int overlap, int shift, int stride) { int num = 0; int num2 = l.n; for (int i = 0; i < shift; i++) { num2 >>= 1; num += num2; } int num3 = num2 >> 1; int num4 = num2 >> 2; int num5 = input_ptr + stride * (num3 - 1); int num6 = output_ptr + (overlap >> 1); short[] bitrev = l.kfft[shift].bitrev; int num7 = 0; for (int i = 0; i < num4; i++) { int num8 = bitrev[num7++]; int num9 = num6 + 2 * num8; output[num9 + 1] = KissFFT.S_MUL(input[num5], l.trig[num + i]) + KissFFT.S_MUL(input[input_ptr], l.trig[num + num4 + i]); output[num9] = KissFFT.S_MUL(input[input_ptr], l.trig[num + i]) - KissFFT.S_MUL(input[num5], l.trig[num + num4 + i]); input_ptr += 2 * stride; num5 -= 2 * stride; } KissFFT.opus_fft_impl(l.kfft[shift], output, output_ptr + (overlap >> 1)); int num10 = output_ptr + (overlap >> 1); int num11 = output_ptr + (overlap >> 1) + num3 - 2; int num12 = num; int num13 = num12 + num4 - 1; int num14 = num12 + num3 - 1; for (int i = 0; i < num4 + 1 >> 1; i++) { int a = output[num10 + 1]; int a2 = output[num10]; short b = l.trig[num12 + i]; short b2 = l.trig[num12 + num4 + i]; int num15 = KissFFT.S_MUL(a, b) + KissFFT.S_MUL(a2, b2); int num16 = KissFFT.S_MUL(a, b2) - KissFFT.S_MUL(a2, b); int a3 = output[num11 + 1]; a2 = output[num11]; output[num10] = num15; output[num11 + 1] = num16; b = l.trig[num13 - i]; b2 = l.trig[num14 - i]; num15 = KissFFT.S_MUL(a3, b) + KissFFT.S_MUL(a2, b2); num16 = KissFFT.S_MUL(a3, b2) - KissFFT.S_MUL(a2, b); output[num11] = num15; output[num10 + 1] = num16; num10 += 2; num11 -= 2; } int index = output_ptr + overlap - 1; num11 = output_ptr; int num17 = 0; int num18 = overlap - 1; for (int i = 0; i < overlap / 2; i++) { int b3 = output[index]; int b4 = output[num11]; output[num11++] = Inlines.MULT16_32_Q15(window[num18], b4) - Inlines.MULT16_32_Q15(window[num17], b3); output[index--] = Inlines.MULT16_32_Q15(window[num17], b4) + Inlines.MULT16_32_Q15(window[num18], b3); num17++; num18--; } } } internal static class Pitch { private static readonly int[] second_check = new int[16] { 0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2 }; internal static void find_best_pitch(Span xcorr, Span y, int len, int max_pitch, int[] best_pitch, int yshift, int maxcorr) { int num = 1; int shift = Inlines.celt_ilog2(maxcorr) - 14; int num2 = -1; int a = -1; int num3 = 0; int b = 0; best_pitch[0] = 0; best_pitch[1] = 1; for (int i = 0; i < len; i++) { num = Inlines.ADD32(num, Inlines.SHR32(Inlines.MULT16_16(y[i], y[i]), yshift)); } for (int j = 0; j < max_pitch; j++) { if (xcorr[j] > 0) { short num4 = Inlines.EXTRACT16(Inlines.VSHR32(xcorr[j], shift)); int num5 = Inlines.MULT16_16_Q15((int)num4, (int)num4); if (Inlines.MULT16_32_Q15(num5, b) > Inlines.MULT16_32_Q15(a, num)) { if (Inlines.MULT16_32_Q15(num5, num3) > Inlines.MULT16_32_Q15(num2, num)) { a = num2; b = num3; best_pitch[1] = best_pitch[0]; num2 = num5; num3 = num; best_pitch[0] = j; } else { a = num5; b = num; best_pitch[1] = j; } } } num += Inlines.SHR32(Inlines.MULT16_16(y[j + len], y[j + len]), yshift) - Inlines.SHR32(Inlines.MULT16_16(y[j], y[j]), yshift); num = Inlines.MAX32(1, num); } } internal static void celt_fir5(int[] x, int[] num, int[] y, int N, int[] mem) { int a = num[0]; int a2 = num[1]; int a3 = num[2]; int a4 = num[3]; int a5 = num[4]; int num2 = mem[0]; int num3 = mem[1]; int num4 = mem[2]; int num5 = mem[3]; int num6 = mem[4]; for (int i = 0; i < N; i++) { int c = Inlines.SHL32(Inlines.EXTEND32(x[i]), 12); c = Inlines.MAC16_16(c, a, num2); c = Inlines.MAC16_16(c, a2, num3); c = Inlines.MAC16_16(c, a3, num4); c = Inlines.MAC16_16(c, a4, num5); c = Inlines.MAC16_16(c, a5, num6); num6 = num5; num5 = num4; num4 = num3; num3 = num2; num2 = x[i]; y[i] = Inlines.ROUND16(c, 12); } mem[0] = num2; mem[1] = num3; mem[2] = num4; mem[3] = num5; mem[4] = num6; } internal static void pitch_downsample(int[][] x, int[] x_lp, int len, int C) { int[] array = new int[5]; int b = 32767; int[] array2 = new int[4]; int[] mem = new int[5]; int[] array3 = new int[5]; int a = 26214; int num = Inlines.celt_maxabs32(x[0], 0, len); if (C == 2) { int b2 = Inlines.celt_maxabs32(x[1], 0, len); num = Inlines.MAX32(num, b2); } if (num < 1) { num = 1; } int num2 = Inlines.celt_ilog2(num) - 10; if (num2 < 0) { num2 = 0; } if (C == 2) { num2++; } int num3 = len >> 1; for (int i = 1; i < num3; i++) { x_lp[i] = Inlines.SHR32(Inlines.HALF32(Inlines.HALF32(x[0][2 * i - 1] + x[0][2 * i + 1]) + x[0][2 * i]), num2); } x_lp[0] = Inlines.SHR32(Inlines.HALF32(Inlines.HALF32(x[0][1]) + x[0][0]), num2); if (C == 2) { for (int i = 1; i < num3; i++) { x_lp[i] += Inlines.SHR32(Inlines.HALF32(Inlines.HALF32(x[1][2 * i - 1] + x[1][2 * i + 1]) + x[1][2 * i]), num2); } x_lp[0] += Inlines.SHR32(Inlines.HALF32(Inlines.HALF32(x[1][1]) + x[1][0]), num2); } Autocorrelation._celt_autocorr(x_lp, array, null, 0, 4, num3); array[0] += Inlines.SHR32(array[0], 13); for (int i = 1; i <= 4; i++) { array[i] -= Inlines.MULT16_32_Q15(2 * i * i, array[i]); } CeltLPC.celt_lpc(array2, array, 4); for (int i = 0; i < 4; i++) { b = Inlines.MULT16_16_Q15(29491, b); array2[i] = Inlines.MULT16_16_Q15(array2[i], b); } array3[0] = array2[0] + 3277; array3[1] = array2[1] + Inlines.MULT16_16_Q15(a, array2[0]); array3[2] = array2[2] + Inlines.MULT16_16_Q15(a, array2[1]); array3[3] = array2[3] + Inlines.MULT16_16_Q15(a, array2[2]); array3[4] = Inlines.MULT16_16_Q15(a, array2[3]); celt_fir5(x_lp, array3, x_lp, num3, mem); } internal static void pitch_search(Span x_lp, int x_lp_ptr, int[] y, int len, int max_pitch, out int pitch) { int[] array = new int[2]; int num = 0; int num2 = len + max_pitch; int[] array2 = new int[len >> 2]; int[] array3 = new int[num2 >> 2]; int[] array4 = new int[max_pitch >> 1]; for (int i = 0; i < len >> 2; i++) { array2[i] = x_lp[x_lp_ptr + 2 * i]; } for (int i = 0; i < num2 >> 2; i++) { array3[i] = y[2 * i]; } int a = Inlines.celt_maxabs32(array2, len >> 2); int b = Inlines.celt_maxabs32(array3, num2 >> 2); num = Inlines.celt_ilog2(Inlines.MAX32(1, Inlines.MAX32(a, b))) - 11; if (num > 0) { for (int i = 0; i < len >> 2; i++) { array2[i] = Inlines.SHR16(array2[i], num); } for (int i = 0; i < num2 >> 2; i++) { array3[i] = Inlines.SHR16(array3[i], num); } num *= 2; } else { num = 0; } int maxcorr = CeltPitchXCorr.pitch_xcorr(array2, 0, array3, 0, array4, len >> 2, max_pitch >> 2); find_best_pitch(array4, array3, len >> 2, max_pitch >> 2, array, 0, maxcorr); maxcorr = 1; for (int j = 0; j < max_pitch >> 1; j++) { array4[j] = 0; if (Inlines.abs(j - 2 * array[0]) <= 2 || Inlines.abs(j - 2 * array[1]) <= 2) { int num3 = 0; for (int i = 0; i < len >> 1; i++) { num3 += Inlines.SHR32(Inlines.MULT16_16(x_lp[x_lp_ptr + i], y[j + i]), num); } array4[j] = Inlines.MAX32(-1, num3); maxcorr = Inlines.MAX32(maxcorr, num3); } } find_best_pitch(array4, y, len >> 1, max_pitch >> 1, array, num + 1, maxcorr); int num7; if (array[0] > 0 && array[0] < (max_pitch >> 1) - 1) { int num4 = array4[array[0] - 1]; int num5 = array4[array[0]]; int num6 = array4[array[0] + 1]; num7 = ((num6 - num4 > Inlines.MULT16_32_Q15((short)22938, num5 - num4)) ? 1 : ((num4 - num6 > Inlines.MULT16_32_Q15((short)22938, num5 - num6)) ? (-1) : 0)); } else { num7 = 0; } pitch = 2 * array[0] - num7; } internal static int remove_doubling(int[] x, int maxperiod, int minperiod, int N, ref int T0_, int prev_period, int prev_gain) { Span span = new int[3]; int num = minperiod; maxperiod /= 2; minperiod /= 2; T0_ /= 2; prev_period /= 2; N /= 2; int num2 = maxperiod; if (T0_ >= maxperiod) { T0_ = maxperiod - 1; } int num3; int num4 = (num3 = T0_); Span span2 = new int[maxperiod + 1]; Span span3 = x.AsSpan(); Span x2 = span3.Slice(num2); span3 = x.AsSpan(); Span y = span3.Slice(num2); span3 = x.AsSpan(); Kernels.dual_inner_prod(x2, y, span3.Slice(num2 - num3), N, out var xy, out var xy2); span2[0] = xy; int num5 = xy; for (int i = 1; i <= maxperiod; i++) { int num6 = num2 - i; num5 = num5 + Inlines.MULT16_16(x[num6], x[num6]) - Inlines.MULT16_16(x[num6 + N], x[num6 + N]); span2[i] = Inlines.MAX32(0, num5); } num5 = span2[num3]; int b = xy2; int num7 = num5; int num8 = 1 + Inlines.HALF32(Inlines.MULT32_32_Q31(xy, num5)); int num9 = Inlines.celt_ilog2(num8) >> 1; int num10 = Inlines.VSHR32(Inlines.MULT16_32_Q15(Inlines.celt_rsqrt_norm(Inlines.VSHR32(num8, 2 * (num9 - 7))), xy2), num9 + 1); int b2 = num10; for (int j = 2; j <= 15; j++) { int num11 = 0; int num12 = Inlines.celt_udiv(2 * num3 + j, 2 * j); if (num12 < minperiod) { break; } int num13 = ((j != 2) ? Inlines.celt_udiv(2 * second_check[j] * num3 + j, 2 * j) : ((num12 + num3 <= maxperiod) ? (num3 + num12) : num3)); span3 = x.AsSpan(); Span x3 = span3.Slice(num2); span3 = x.AsSpan(); Span y2 = span3.Slice(num2 - num12); span3 = x.AsSpan(); Kernels.dual_inner_prod(x3, y2, span3.Slice(num2 - num13), N, out xy2, out var xy3); xy2 += xy3; num5 = span2[num12] + span2[num13]; int num14 = 1 + Inlines.MULT32_32_Q31(xy, num5); int num15 = Inlines.celt_ilog2(num14) >> 1; int num16 = Inlines.VSHR32(Inlines.MULT16_32_Q15(Inlines.celt_rsqrt_norm(Inlines.VSHR32(num14, 2 * (num15 - 7))), xy2), num15 + 1); num11 = ((Inlines.abs(num12 - prev_period) <= 1) ? prev_gain : ((Inlines.abs(num12 - prev_period) <= 2 && 5 * j * j < num3) ? Inlines.HALF16(prev_gain) : 0)); int num17 = Inlines.MAX16(9830, Inlines.MULT16_16_Q15(22938, b2) - num11); if (num12 < 3 * minperiod) { num17 = Inlines.MAX16(13107, Inlines.MULT16_16_Q15(27853, b2) - num11); } else if (num12 < 2 * minperiod) { num17 = Inlines.MAX16(16384, Inlines.MULT16_16_Q15(29491, b2) - num11); } if (num16 > num17) { b = xy2; num7 = num5; num4 = num12; num10 = num16; } } b = Inlines.MAX32(0, b); int num18 = ((num7 > b) ? Inlines.SHR32(Inlines.frac_div32(b, num7 + 1), 16) : 32767); for (int j = 0; j < 3; j++) { ref int reference = ref span[j]; span3 = x.AsSpan(); Span x4 = span3.Slice(num2); span3 = x.AsSpan(); reference = Kernels.celt_inner_prod(x4, span3.Slice(num2 - (num4 + j - 1)), N); } int num19 = ((span[2] - span[0] > Inlines.MULT16_32_Q15((short)22938, span[1] - span[0])) ? 1 : ((span[0] - span[2] > Inlines.MULT16_32_Q15((short)22938, span[1] - span[2])) ? (-1) : 0)); if (num18 > num10) { num18 = num10; } T0_ = 2 * num4 + num19; if (T0_ < num) { T0_ = num; } return num18; } } internal static class QuantizeBands { private static readonly int[] pred_coef = new int[4] { 29440, 26112, 21248, 16384 }; private static readonly int[] beta_coef = new int[4] { 30147, 22282, 12124, 6554 }; private static readonly int beta_intra = 4915; private static byte[] small_energy_icdf = new byte[3] { 2, 1, 0 }; internal static int loss_distortion(int[][] eBands, int[][] oldEBands, int start, int end, int len, int C) { int num = 0; int num2 = 0; do { for (int i = start; i < end; i++) { int num3 = Inlines.SUB16(Inlines.SHR16(eBands[num2][i], 3), Inlines.SHR16(oldEBands[num2][i], 3)); num = Inlines.MAC16_16(num, num3, num3); } } while (++num2 < C); return Inlines.MIN32(200, Inlines.SHR32(num, 14)); } internal static int quant_coarse_energy_impl(CeltMode m, int start, int end, int[][] eBands, int[][] oldEBands, int budget, int tell, byte[] prob_model, int[][] error, EntropyCoder enc, Span encodedData, int C, int LM, int intra, int max_decay, int lfe) { int num = 0; int[] array = new int[2]; if (tell + 3 <= budget) { enc.enc_bit_logp(encodedData, intra, 3u); } int a; int a2; if (intra != 0) { a = 0; a2 = beta_intra; } else { a2 = beta_coef[LM]; a = pred_coef[LM]; } for (int i = start; i < end; i++) { int num2 = 0; do { int num3 = eBands[num2][i]; int b = Inlines.MAX16(-9216, oldEBands[num2][i]); int num4 = Inlines.SHL32(Inlines.EXTEND32(num3), 7) - Inlines.PSHR32(Inlines.MULT16_16(a, b), 8) - array[num2]; int value = num4 + 65536 >> 17; int num5 = Inlines.EXTRACT16(Inlines.MAX32(-28672, Inlines.SUB32(oldEBands[num2][i], max_decay))); if (value < 0 && num3 < num5) { value += Inlines.SHR16(Inlines.SUB16(num5, num3), 10); if (value > 0) { value = 0; } } int num6 = value; tell = enc.tell(); int num7 = budget - tell - 3 * C * (end - i); if (i != start && num7 < 30) { if (num7 < 24) { value = Inlines.IMIN(1, value); } if (num7 < 16) { value = Inlines.IMAX(-1, value); } } if (lfe != 0 && i >= 2) { value = Inlines.IMIN(value, 0); } if (budget - tell >= 15) { int num8 = 2 * Inlines.IMIN(i, 20); Laplace.ec_laplace_encode(enc, encodedData, ref value, (uint)(prob_model[num8] << 7), prob_model[num8 + 1] << 6); } else if (budget - tell >= 2) { value = Inlines.IMAX(-1, Inlines.IMIN(value, 1)); enc.enc_icdf(encodedData, (2 * value) ^ (0 - ((value < 0) ? 1 : 0)), small_energy_icdf, 2u); } else if (budget - tell >= 1) { value = Inlines.IMIN(0, value); enc.enc_bit_logp(encodedData, -value, 1u); } else { value = -1; } error[num2][i] = Inlines.PSHR32(num4, 7) - Inlines.SHL16(value, 10); num += Inlines.abs(num6 - value); int a3 = Inlines.SHL32(value, 10); int b2 = Inlines.PSHR32(Inlines.MULT16_16(a, b), 8) + array[num2] + Inlines.SHL32(a3, 7); b2 = Inlines.MAX32(-3670016, b2); oldEBands[num2][i] = Inlines.PSHR32(b2, 7); array[num2] = array[num2] + Inlines.SHL32(a3, 7) - Inlines.MULT16_16(a2, Inlines.PSHR32(a3, 8)); } while (++num2 < C); } if (lfe == 0) { return num; } return 0; } internal static void quant_coarse_energy(CeltMode m, int start, int end, int effEnd, int[][] eBands, int[][] oldEBands, uint budget, int[][] error, EntropyCoder enc, Span encodedData, int C, int LM, int nbAvailableBytes, int force_intra, ref int delayedIntra, int two_pass, int loss_rate, int lfe) { EntropyCoder entropyCoder = new EntropyCoder(); int num = 0; int num2 = ((force_intra != 0 || (two_pass == 0 && delayedIntra > 2 * C * (end - start) && nbAvailableBytes > (end - start) * C)) ? 1 : 0); int num3 = (int)(budget * delayedIntra * loss_rate / (C * 512)); int num4 = loss_distortion(eBands, oldEBands, start, effEnd, m.nbEBands, C); uint num5 = (uint)enc.tell(); if (num5 + 3 > budget) { two_pass = (num2 = 0); } int num6 = 16384; if (end - start > 10) { num6 = Inlines.MIN32(num6, Inlines.SHL32(nbAvailableBytes, 7)); } if (lfe != 0) { num6 = 3072; } entropyCoder.Assign(enc); int[][] array = Arrays.InitTwoDimensionalArray(C, m.nbEBands); int[][] array2 = Arrays.InitTwoDimensionalArray(C, m.nbEBands); Arrays.MemCopy(oldEBands[0], 0, array[0], 0, m.nbEBands); if (C == 2) { Arrays.MemCopy(oldEBands[1], 0, array[1], 0, m.nbEBands); } if (two_pass != 0 || num2 != 0) { num = quant_coarse_energy_impl(m, start, end, eBands, array, (int)budget, (int)num5, Tables.e_prob_model[LM][1], array2, enc, encodedData, C, LM, 1, num6, lfe); } if (num2 == 0) { EntropyCoder entropyCoder2 = new EntropyCoder(); byte[] array3 = null; int num7 = (int)enc.tell_frac(); entropyCoder2.Assign(enc); uint num8 = entropyCoder.range_bytes(); uint num9 = entropyCoder2.range_bytes(); int start2 = (int)num8; uint num10 = num9 - num8; if (num10 != 0) { array3 = new byte[num10]; encodedData.Slice(start2, (int)num10).CopyTo(array3); } enc.Assign(entropyCoder); int num11 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands, (int)budget, (int)num5, Tables.e_prob_model[LM][num2], error, enc, encodedData, C, LM, 0, num6, lfe); if (two_pass != 0 && (num < num11 || (num == num11 && (int)enc.tell_frac() + num3 > num7))) { enc.Assign(entropyCoder2); array3?.AsSpan(0, (int)(num9 - num8)).CopyTo(encodedData.Slice(start2)); Arrays.MemCopy(array[0], 0, oldEBands[0], 0, m.nbEBands); Arrays.MemCopy(array2[0], 0, error[0], 0, m.nbEBands); if (C == 2) { Arrays.MemCopy(array[1], 0, oldEBands[1], 0, m.nbEBands); Arrays.MemCopy(array2[1], 0, error[1], 0, m.nbEBands); } num2 = 1; } } else { Arrays.MemCopy(array[0], 0, oldEBands[0], 0, m.nbEBands); Arrays.MemCopy(array2[0], 0, error[0], 0, m.nbEBands); if (C == 2) { Arrays.MemCopy(array[1], 0, oldEBands[1], 0, m.nbEBands); Arrays.MemCopy(array2[1], 0, error[1], 0, m.nbEBands); } } if (num2 != 0) { delayedIntra = num4; } else { delayedIntra = Inlines.ADD32(Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15(pred_coef[LM], pred_coef[LM]), delayedIntra), num4); } } internal static void quant_fine_energy(CeltMode m, int start, int end, int[][] oldEBands, int[][] error, int[] fine_quant, EntropyCoder enc, Span encodedData, int C) { for (int i = start; i < end; i++) { int num = 1 << fine_quant[i]; if (fine_quant[i] <= 0) { continue; } int num2 = 0; do { int num3 = error[num2][i] + 512 >> 10 - fine_quant[i]; if (num3 > num - 1) { num3 = num - 1; } if (num3 < 0) { num3 = 0; } enc.enc_bits(encodedData, (uint)num3, (uint)fine_quant[i]); int num4 = Inlines.SUB16(Inlines.SHR32(Inlines.SHL32(num3, 10) + 512, fine_quant[i]), 512); oldEBands[num2][i] += num4; error[num2][i] -= num4; } while (++num2 < C); } } internal static void quant_energy_finalise(CeltMode m, int start, int end, int[][] oldEBands, int[][] error, int[] fine_quant, int[] fine_priority, int bits_left, EntropyCoder enc, Span encodedData, int C) { for (int i = 0; i < 2; i++) { for (int j = start; j < end; j++) { if (bits_left < C) { break; } if (fine_quant[j] < 8 && fine_priority[j] == i) { int num = 0; do { int num2 = ((error[num][j] >= 0) ? 1 : 0); enc.enc_bits(encodedData, (uint)num2, 1u); int num3 = Inlines.SHR16(Inlines.SHL16(num2, 10) - 512, fine_quant[j] + 1); oldEBands[num][j] += num3; bits_left--; } while (++num < C); } } } } internal static void unquant_coarse_energy(CeltMode m, int start, int end, int[] oldEBands, int intra, EntropyCoder dec, ReadOnlySpan encodedData, int C, int LM) { byte[] array = Tables.e_prob_model[LM][intra]; int[] array2 = new int[2]; int a; int a2; if (intra != 0) { a = 0; a2 = beta_intra; } else { a2 = beta_coef[LM]; a = pred_coef[LM]; } int num = (int)(dec.storage * 8); for (int i = start; i < end; i++) { int num2 = 0; do { int num3 = dec.tell(); int a3; if (num - num3 >= 15) { int num4 = 2 * Inlines.IMIN(i, 20); a3 = Laplace.ec_laplace_decode(dec, encodedData, (uint)(array[num4] << 7), array[num4 + 1] << 6); } else if (num - num3 < 2) { a3 = ((num - num3 < 1) ? (-1) : (-dec.dec_bit_logp(encodedData, 1u))); } else { a3 = dec.dec_icdf(encodedData, small_energy_icdf, 2u); a3 = (a3 >> 1) ^ -(a3 & 1); } int a4 = Inlines.SHL32(a3, 10); oldEBands[i + num2 * m.nbEBands] = Inlines.MAX16(-9216, oldEBands[i + num2 * m.nbEBands]); int b = Inlines.PSHR32(Inlines.MULT16_16(a, oldEBands[i + num2 * m.nbEBands]), 8) + array2[num2] + Inlines.SHL32(a4, 7); b = Inlines.MAX32(-3670016, b); oldEBands[i + num2 * m.nbEBands] = Inlines.PSHR32(b, 7); array2[num2] = array2[num2] + Inlines.SHL32(a4, 7) - Inlines.MULT16_16(a2, Inlines.PSHR32(a4, 8)); } while (++num2 < C); } } internal static void unquant_fine_energy(CeltMode m, int start, int end, int[] oldEBands, int[] fine_quant, EntropyCoder dec, ReadOnlySpan encodedData, int C) { for (int i = start; i < end; i++) { if (fine_quant[i] > 0) { int num = 0; do { int num2 = Inlines.SUB16(Inlines.SHR32(Inlines.SHL32((int)dec.dec_bits(encodedData, (uint)fine_quant[i]), 10) + 512, fine_quant[i]), 512); oldEBands[i + num * m.nbEBands] += num2; } while (++num < C); } } } internal static void unquant_energy_finalise(CeltMode m, int start, int end, int[] oldEBands, int[] fine_quant, int[] fine_priority, int bits_left, EntropyCoder dec, ReadOnlySpan encodedData, int C) { for (int i = 0; i < 2; i++) { for (int j = start; j < end; j++) { if (bits_left < C) { break; } if (fine_quant[j] < 8 && fine_priority[j] == i) { int num = 0; do { int num2 = Inlines.SHR16(Inlines.SHL16((int)dec.dec_bits(encodedData, 1u), 10) - 512, fine_quant[j] + 1); oldEBands[j + num * m.nbEBands] += num2; bits_left--; } while (++num < C); } } } } internal static void amp2Log2(CeltMode m, int effEnd, int end, int[][] bandE, int[][] bandLogE, int C) { int num = 0; do { for (int i = 0; i < effEnd; i++) { bandLogE[num][i] = Inlines.celt_log2(Inlines.SHL32(bandE[num][i], 2)) - Inlines.SHL16((int)Tables.eMeans[i], 6); } for (int i = effEnd; i < end; i++) { bandLogE[num][i] = -14336; } } while (++num < C); } internal static void amp2Log2(CeltMode m, int effEnd, int end, int[] bandE, Span bandLogE, int bandLogE_ptr, int C) { int num = 0; do { for (int i = 0; i < effEnd; i++) { bandLogE[bandLogE_ptr + num * m.nbEBands + i] = Inlines.celt_log2(Inlines.SHL32(bandE[i + num * m.nbEBands], 2)) - Inlines.SHL16((int)Tables.eMeans[i], 6); } for (int i = effEnd; i < end; i++) { bandLogE[bandLogE_ptr + num * m.nbEBands + i] = -14336; } } while (++num < C); } } internal static class Rate { private static readonly byte[] LOG2_FRAC_TABLE = new byte[24] { 0, 8, 13, 16, 19, 21, 23, 24, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 34, 35, 36, 36, 37, 37 }; private const int ALLOC_STEPS = 6; internal static int get_pulses(int i) { if (i >= 8) { return 8 + (i & 7) << (i >> 3) - 1; } return i; } internal static int bits2pulses(CeltMode m, int band, int LM, int bits) { LM++; byte[] bits2 = m.cache.bits; int num = m.cache.index[LM * m.nbEBands + band]; int num2 = 0; int num3 = bits2[num]; bits--; for (int i = 0; i < 6; i++) { int num4 = num2 + num3 + 1 >> 1; if (bits2[num + num4] >= bits) { num3 = num4; } else { num2 = num4; } } if (bits - ((num2 == 0) ? (-1) : bits2[num + num2]) <= bits2[num + num3] - bits) { return num2; } return num3; } internal static int pulses2bits(CeltMode m, int band, int LM, int pulses) { LM++; if (pulses != 0) { return m.cache.bits[m.cache.index[LM * m.nbEBands + band] + pulses] + 1; } return 0; } internal static int interp_bits2pulses_encode(CeltMode m, int start, int end, int skip_start, int[] bits1, int[] bits2, int[] thresh, int[] cap, int total, out int _balance, int skip_rsv, ref int intensity, int intensity_rsv, ref int dual_stereo, int dual_stereo_rsv, int[] bits, int[] ebits, int[] fine_priority, int C, int LM, EntropyCoder ec, Span encodedData, int prev, int signalBandwidth) { int num = -1; int num2 = C << 3; int num3 = ((C > 1) ? 1 : 0); int num4 = LM << 3; int num5 = 0; int num6 = 64; int num9; int num8; int num10; for (int i = 0; i < 6; i++) { int num7 = num5 + num6 >> 1; num8 = 0; num9 = 0; num10 = end; while (num10-- > start) { int num11 = bits1[num10] + (num7 * bits2[num10] >> 6); if (num11 >= thresh[num10] || num9 != 0) { num9 = 1; num8 += Inlines.IMIN(num11, cap[num10]); } else if (num11 >= num2) { num8 += num2; } } if (num8 > total) { num6 = num7; } else { num5 = num7; } } num8 = 0; num9 = 0; num10 = end; while (num10-- > start) { int num12 = bits1[num10] + (num5 * bits2[num10] >> 6); if (num12 < thresh[num10] && num9 == 0) { num12 = ((num12 >= num2) ? num2 : 0); } else { num9 = 1; } num8 += (bits[num10] = Inlines.IMIN(num12, cap[num10])); } num = end; int num14; int num13; while (true) { num10 = num - 1; if (num10 <= skip_start) { total += skip_rsv; break; } num13 = total - num8; num14 = Inlines.celt_udiv(num13, m.eBands[num] - m.eBands[start]); num13 -= (m.eBands[num] - m.eBands[start]) * num14; int num15 = Inlines.IMAX(num13 - (m.eBands[num10] - m.eBands[start]), 0); int num16 = m.eBands[num] - m.eBands[num10]; int num17 = bits[num10] + num14 * num16 + num15; if (num17 >= Inlines.IMAX(thresh[num10], num2 + 8)) { if (num <= start + 2 || (num17 > ((num10 < prev) ? 7 : 9) * num16 << LM << 3 >> 4 && num10 <= signalBandwidth)) { ec.enc_bit_logp(encodedData, 1, 1u); break; } ec.enc_bit_logp(encodedData, 0, 1u); num8 += 8; num17 -= 8; } num8 -= bits[num10] + intensity_rsv; if (intensity_rsv > 0) { intensity_rsv = LOG2_FRAC_TABLE[num10 - start]; } num8 += intensity_rsv; if (num17 >= num2) { num8 += num2; bits[num10] = num2; } else { bits[num10] = 0; } num--; } if (intensity_rsv > 0) { intensity = Inlines.IMIN(intensity, num); ec.enc_uint(encodedData, (uint)(intensity - start), (uint)(num + 1 - start)); } else { intensity = 0; } if (intensity <= start) { total += dual_stereo_rsv; dual_stereo_rsv = 0; } if (dual_stereo_rsv > 0) { ec.enc_bit_logp(encodedData, dual_stereo, 1u); } else { dual_stereo = 0; } num13 = total - num8; num14 = Inlines.celt_udiv(num13, m.eBands[num] - m.eBands[start]); num13 -= (m.eBands[num] - m.eBands[start]) * num14; for (num10 = start; num10 < num; num10++) { bits[num10] += num14 * (m.eBands[num10 + 1] - m.eBands[num10]); } for (num10 = start; num10 < num; num10++) { int num18 = Inlines.IMIN(num13, m.eBands[num10 + 1] - m.eBands[num10]); bits[num10] += num18; num13 -= num18; } int num19 = 0; for (num10 = start; num10 < num; num10++) { int num20 = m.eBands[num10 + 1] - m.eBands[num10] << LM; int num21 = bits[num10] + num19; int num22; if (num20 > 1) { num22 = Inlines.MAX32(num21 - cap[num10], 0); bits[num10] = num21 - num22; int num23 = C * num20 + ((C == 2 && num20 > 2 && dual_stereo == 0 && num10 < intensity) ? 1 : 0); int num24 = num23 * (m.logN[num10] + num4); int num25 = (num24 >> 1) - num23 * 21; if (num20 == 2) { num25 += num23 << 3 >> 2; } if (bits[num10] + num25 < num23 * 2 << 3) { num25 += num24 >> 2; } else if (bits[num10] + num25 < num23 * 3 << 3) { num25 += num24 >> 3; } ebits[num10] = Inlines.IMAX(0, bits[num10] + num25 + (num23 << 2)); ebits[num10] = Inlines.celt_udiv(ebits[num10], num23) >> 3; if (C * ebits[num10] > bits[num10] >> 3) { ebits[num10] = bits[num10] >> num3 >> 3; } ebits[num10] = Inlines.IMIN(ebits[num10], 8); fine_priority[num10] = ((ebits[num10] * (num23 << 3) >= bits[num10] + num25) ? 1 : 0); bits[num10] -= C * ebits[num10] << 3; } else { num22 = Inlines.MAX32(0, num21 - (C << 3)); bits[num10] = num21 - num22; ebits[num10] = 0; fine_priority[num10] = 1; } if (num22 > 0) { int num26 = Inlines.IMIN(num22 >> num3 + 3, 8 - ebits[num10]); ebits[num10] += num26; int num27 = num26 * C << 3; fine_priority[num10] = ((num27 >= num22 - num19) ? 1 : 0); num22 -= num27; } num19 = num22; } _balance = num19; for (; num10 < end; num10++) { ebits[num10] = bits[num10] >> num3 >> 3; bits[num10] = 0; fine_priority[num10] = ((ebits[num10] < 1) ? 1 : 0); } return num; } internal static int interp_bits2pulses_decode(CeltMode m, int start, int end, int skip_start, int[] bits1, int[] bits2, int[] thresh, int[] cap, int total, out int _balance, int skip_rsv, ref int intensity, int intensity_rsv, ref int dual_stereo, int dual_stereo_rsv, int[] bits, int[] ebits, int[] fine_priority, int C, int LM, EntropyCoder ec, ReadOnlySpan encodedData, int prev, int signalBandwidth) { int num = -1; int num2 = C << 3; int num3 = ((C > 1) ? 1 : 0); int num4 = LM << 3; int num5 = 0; int num6 = 64; int num9; int num8; int num10; for (int i = 0; i < 6; i++) { int num7 = num5 + num6 >> 1; num8 = 0; num9 = 0; num10 = end; while (num10-- > start) { int num11 = bits1[num10] + (num7 * bits2[num10] >> 6); if (num11 >= thresh[num10] || num9 != 0) { num9 = 1; num8 += Inlines.IMIN(num11, cap[num10]); } else if (num11 >= num2) { num8 += num2; } } if (num8 > total) { num6 = num7; } else { num5 = num7; } } num8 = 0; num9 = 0; num10 = end; while (num10-- > start) { int num12 = bits1[num10] + (num5 * bits2[num10] >> 6); if (num12 < thresh[num10] && num9 == 0) { num12 = ((num12 >= num2) ? num2 : 0); } else { num9 = 1; } num8 += (bits[num10] = Inlines.IMIN(num12, cap[num10])); } num = end; int num14; int num13; while (true) { num10 = num - 1; if (num10 <= skip_start) { total += skip_rsv; break; } num13 = total - num8; num14 = Inlines.celt_udiv(num13, m.eBands[num] - m.eBands[start]); num13 -= (m.eBands[num] - m.eBands[start]) * num14; int num15 = Inlines.IMAX(num13 - (m.eBands[num10] - m.eBands[start]), 0); int num16 = m.eBands[num] - m.eBands[num10]; int num17 = bits[num10] + num14 * num16 + num15; if (num17 >= Inlines.IMAX(thresh[num10], num2 + 8)) { if (ec.dec_bit_logp(encodedData, 1u) != 0) { break; } num8 += 8; num17 -= 8; } num8 -= bits[num10] + intensity_rsv; if (intensity_rsv > 0) { intensity_rsv = LOG2_FRAC_TABLE[num10 - start]; } num8 += intensity_rsv; if (num17 >= num2) { num8 += num2; bits[num10] = num2; } else { bits[num10] = 0; } num--; } if (intensity_rsv > 0) { intensity = start + (int)ec.dec_uint(encodedData, (uint)(num + 1 - start)); } else { intensity = 0; } if (intensity <= start) { total += dual_stereo_rsv; dual_stereo_rsv = 0; } if (dual_stereo_rsv > 0) { dual_stereo = ec.dec_bit_logp(encodedData, 1u); } else { dual_stereo = 0; } num13 = total - num8; num14 = Inlines.celt_udiv(num13, m.eBands[num] - m.eBands[start]); num13 -= (m.eBands[num] - m.eBands[start]) * num14; for (num10 = start; num10 < num; num10++) { bits[num10] += num14 * (m.eBands[num10 + 1] - m.eBands[num10]); } for (num10 = start; num10 < num; num10++) { int num18 = Inlines.IMIN(num13, m.eBands[num10 + 1] - m.eBands[num10]); bits[num10] += num18; num13 -= num18; } int num19 = 0; for (num10 = start; num10 < num; num10++) { int num20 = m.eBands[num10 + 1] - m.eBands[num10] << LM; int num21 = bits[num10] + num19; int num22; if (num20 > 1) { num22 = Inlines.MAX32(num21 - cap[num10], 0); bits[num10] = num21 - num22; int num23 = C * num20 + ((C == 2 && num20 > 2 && dual_stereo == 0 && num10 < intensity) ? 1 : 0); int num24 = num23 * (m.logN[num10] + num4); int num25 = (num24 >> 1) - num23 * 21; if (num20 == 2) { num25 += num23 << 3 >> 2; } if (bits[num10] + num25 < num23 * 2 << 3) { num25 += num24 >> 2; } else if (bits[num10] + num25 < num23 * 3 << 3) { num25 += num24 >> 3; } ebits[num10] = Inlines.IMAX(0, bits[num10] + num25 + (num23 << 2)); ebits[num10] = Inlines.celt_udiv(ebits[num10], num23) >> 3; if (C * ebits[num10] > bits[num10] >> 3) { ebits[num10] = bits[num10] >> num3 >> 3; } ebits[num10] = Inlines.IMIN(ebits[num10], 8); fine_priority[num10] = ((ebits[num10] * (num23 << 3) >= bits[num10] + num25) ? 1 : 0); bits[num10] -= C * ebits[num10] << 3; } else { num22 = Inlines.MAX32(0, num21 - (C << 3)); bits[num10] = num21 - num22; ebits[num10] = 0; fine_priority[num10] = 1; } if (num22 > 0) { int num26 = Inlines.IMIN(num22 >> num3 + 3, 8 - ebits[num10]); ebits[num10] += num26; int num27 = num26 * C << 3; fine_priority[num10] = ((num27 >= num22 - num19) ? 1 : 0); num22 -= num27; } num19 = num22; } _balance = num19; for (; num10 < end; num10++) { ebits[num10] = bits[num10] >> num3 >> 3; bits[num10] = 0; fine_priority[num10] = ((ebits[num10] < 1) ? 1 : 0); } return num; } internal static int compute_allocation_encode(CeltMode m, int start, int end, int[] offsets, int[] cap, int alloc_trim, ref int intensity, ref int dual_stereo, int total, out int balance, int[] pulses, int[] ebits, int[] fine_priority, int C, int LM, EntropyCoder ec, Span encodedData, int prev, int signalBandwidth) { total = Inlines.IMAX(total, 0); int nbEBands = m.nbEBands; int skip_start = start; int num = ((total >= 8) ? 8 : 0); total -= num; int num2; int num3 = (num2 = 0); if (C == 2) { num3 = LOG2_FRAC_TABLE[end - start]; if (num3 > total) { num3 = 0; } else { total -= num3; num2 = ((total >= 8) ? 8 : 0); total -= num2; } } int[] array = new int[nbEBands]; int[] array2 = new int[nbEBands]; int[] array3 = new int[nbEBands]; int[] array4 = new int[nbEBands]; for (int i = start; i < end; i++) { array3[i] = Inlines.IMAX(C << 3, 3 * (m.eBands[i + 1] - m.eBands[i]) << LM << 3 >> 4); array4[i] = C * (m.eBands[i + 1] - m.eBands[i]) * (alloc_trim - 5 - LM) * (end - i - 1) * (1 << LM + 3) >> 6; if (m.eBands[i + 1] - m.eBands[i] << LM == 1) { array4[i] -= C << 3; } } int num4 = 1; int num5 = m.nbAllocVectors - 1; do { int num6 = 0; int num7 = 0; int num8 = num4 + num5 >> 1; int i = end; while (i-- > start) { int num9 = m.eBands[i + 1] - m.eBands[i]; int num10 = C * num9 * m.allocVectors[num8 * nbEBands + i] << LM >> 2; if (num10 > 0) { num10 = Inlines.IMAX(0, num10 + array4[i]); } num10 += offsets[i]; if (num10 >= array3[i] || num6 != 0) { num6 = 1; num7 += Inlines.IMIN(num10, cap[i]); } else if (num10 >= C << 3) { num7 += C << 3; } } if (num7 > total) { num5 = num8 - 1; } else { num4 = num8 + 1; } } while (num4 <= num5); num5 = num4--; for (int i = start; i < end; i++) { int num11 = m.eBands[i + 1] - m.eBands[i]; int num12 = C * num11 * m.allocVectors[num4 * nbEBands + i] << LM >> 2; int num13 = ((num5 >= m.nbAllocVectors) ? cap[i] : (C * num11 * m.allocVectors[num5 * nbEBands + i] << LM >> 2)); if (num12 > 0) { num12 = Inlines.IMAX(0, num12 + array4[i]); } if (num13 > 0) { num13 = Inlines.IMAX(0, num13 + array4[i]); } if (num4 > 0) { num12 += offsets[i]; } num13 += offsets[i]; if (offsets[i] > 0) { skip_start = i; } num13 = Inlines.IMAX(0, num13 - num12); array[i] = num12; array2[i] = num13; } return interp_bits2pulses_encode(m, start, end, skip_start, array, array2, array3, cap, total, out balance, num, ref intensity, num3, ref dual_stereo, num2, pulses, ebits, fine_priority, C, LM, ec, encodedData, prev, signalBandwidth); } internal static int compute_allocation_decode(CeltMode m, int start, int end, int[] offsets, int[] cap, int alloc_trim, ref int intensity, ref int dual_stereo, int total, out int balance, int[] pulses, int[] ebits, int[] fine_priority, int C, int LM, EntropyCoder ec, ReadOnlySpan encodedData, int prev, int signalBandwidth) { total = Inlines.IMAX(total, 0); int nbEBands = m.nbEBands; int skip_start = start; int num = ((total >= 8) ? 8 : 0); total -= num; int num2; int num3 = (num2 = 0); if (C == 2) { num3 = LOG2_FRAC_TABLE[end - start]; if (num3 > total) { num3 = 0; } else { total -= num3; num2 = ((total >= 8) ? 8 : 0); total -= num2; } } int[] array = new int[nbEBands]; int[] array2 = new int[nbEBands]; int[] array3 = new int[nbEBands]; int[] array4 = new int[nbEBands]; for (int i = start; i < end; i++) { array3[i] = Inlines.IMAX(C << 3, 3 * (m.eBands[i + 1] - m.eBands[i]) << LM << 3 >> 4); array4[i] = C * (m.eBands[i + 1] - m.eBands[i]) * (alloc_trim - 5 - LM) * (end - i - 1) * (1 << LM + 3) >> 6; if (m.eBands[i + 1] - m.eBands[i] << LM == 1) { array4[i] -= C << 3; } } int num4 = 1; int num5 = m.nbAllocVectors - 1; do { int num6 = 0; int num7 = 0; int num8 = num4 + num5 >> 1; int i = end; while (i-- > start) { int num9 = m.eBands[i + 1] - m.eBands[i]; int num10 = C * num9 * m.allocVectors[num8 * nbEBands + i] << LM >> 2; if (num10 > 0) { num10 = Inlines.IMAX(0, num10 + array4[i]); } num10 += offsets[i]; if (num10 >= array3[i] || num6 != 0) { num6 = 1; num7 += Inlines.IMIN(num10, cap[i]); } else if (num10 >= C << 3) { num7 += C << 3; } } if (num7 > total) { num5 = num8 - 1; } else { num4 = num8 + 1; } } while (num4 <= num5); num5 = num4--; for (int i = start; i < end; i++) { int num11 = m.eBands[i + 1] - m.eBands[i]; int num12 = C * num11 * m.allocVectors[num4 * nbEBands + i] << LM >> 2; int num13 = ((num5 >= m.nbAllocVectors) ? cap[i] : (C * num11 * m.allocVectors[num5 * nbEBands + i] << LM >> 2)); if (num12 > 0) { num12 = Inlines.IMAX(0, num12 + array4[i]); } if (num13 > 0) { num13 = Inlines.IMAX(0, num13 + array4[i]); } if (num4 > 0) { num12 += offsets[i]; } num13 += offsets[i]; if (offsets[i] > 0) { skip_start = i; } num13 = Inlines.IMAX(0, num13 - num12); array[i] = num12; array2[i] = num13; } return interp_bits2pulses_decode(m, start, end, skip_start, array, array2, array3, cap, total, out balance, num, ref intensity, num3, ref dual_stereo, num2, pulses, ebits, fine_priority, C, LM, ec, encodedData, prev, signalBandwidth); } } internal static class Tables { internal static readonly byte[] eMeans = new byte[25] { 103, 100, 92, 85, 81, 77, 72, 70, 78, 75, 73, 71, 78, 74, 69, 72, 70, 74, 76, 71, 60, 60, 60, 60, 60 }; internal static readonly int[] ordery_table = new int[30] { 1, 0, 3, 0, 2, 1, 7, 0, 4, 3, 6, 1, 5, 2, 15, 0, 8, 7, 12, 3, 11, 4, 14, 1, 9, 6, 13, 2, 10, 5 }; internal static readonly short[] eband5ms = new short[22] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100 }; internal static readonly byte[][][] e_prob_model = new byte[4][][] { new byte[2][] { new byte[42] { 72, 127, 65, 129, 66, 128, 65, 128, 64, 128, 62, 128, 64, 128, 64, 128, 92, 78, 92, 79, 92, 78, 90, 79, 116, 41, 115, 40, 114, 40, 132, 26, 132, 26, 145, 17, 161, 12, 176, 10, 177, 11 }, new byte[42] { 24, 179, 48, 138, 54, 135, 54, 132, 53, 134, 56, 133, 55, 132, 55, 132, 61, 114, 70, 96, 74, 88, 75, 88, 87, 74, 89, 66, 91, 67, 100, 59, 108, 50, 120, 40, 122, 37, 97, 43, 78, 50 } }, new byte[2][] { new byte[42] { 83, 78, 84, 81, 88, 75, 86, 74, 87, 71, 90, 73, 93, 74, 93, 74, 109, 40, 114, 36, 117, 34, 117, 34, 143, 17, 145, 18, 146, 19, 162, 12, 165, 10, 178, 7, 189, 6, 190, 8, 177, 9 }, new byte[42] { 23, 178, 54, 115, 63, 102, 66, 98, 69, 99, 74, 89, 71, 91, 73, 91, 78, 89, 86, 80, 92, 66, 93, 64, 102, 59, 103, 60, 104, 60, 117, 52, 123, 44, 138, 35, 133, 31, 97, 38, 77, 45 } }, new byte[2][] { new byte[42] { 61, 90, 93, 60, 105, 42, 107, 41, 110, 45, 116, 38, 113, 38, 112, 38, 124, 26, 132, 27, 136, 19, 140, 20, 155, 14, 159, 16, 158, 18, 170, 13, 177, 10, 187, 8, 192, 6, 175, 9, 159, 10 }, new byte[42] { 21, 178, 59, 110, 71, 86, 75, 85, 84, 83, 91, 66, 88, 73, 87, 72, 92, 75, 98, 72, 105, 58, 107, 54, 115, 52, 114, 55, 112, 56, 129, 51, 132, 40, 150, 33, 140, 29, 98, 35, 77, 42 } }, new byte[2][] { new byte[42] { 42, 121, 96, 66, 108, 43, 111, 40, 117, 44, 123, 32, 120, 36, 119, 33, 127, 33, 134, 34, 139, 21, 147, 23, 152, 20, 158, 25, 154, 26, 166, 21, 173, 16, 184, 13, 184, 10, 150, 13, 139, 15 }, new byte[42] { 22, 178, 63, 114, 74, 82, 84, 83, 92, 82, 103, 62, 96, 72, 96, 67, 101, 73, 107, 72, 113, 55, 118, 52, 125, 52, 118, 52, 117, 55, 135, 49, 137, 39, 157, 32, 145, 29, 97, 33, 77, 40 } } }; internal static readonly sbyte[][] tf_select_table = new sbyte[4][] { new sbyte[8] { 0, -1, 0, -1, 0, -1, 0, -1 }, new sbyte[8] { 0, -1, 0, -2, 1, 0, 1, -1 }, new sbyte[8] { 0, -2, 0, -3, 2, 0, 1, -1 }, new sbyte[8] { 0, -2, 0, -3, 3, 0, 1, -1 } }; internal static readonly byte[] trim_icdf = new byte[11] { 126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0 }; internal static readonly byte[] spread_icdf = new byte[4] { 25, 23, 2, 0 }; internal static readonly byte[] tapset_icdf = new byte[3] { 2, 1, 0 }; internal static readonly byte[] band_allocation = new byte[231] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 80, 75, 69, 63, 56, 49, 40, 34, 29, 20, 18, 10, 0, 0, 0, 0, 0, 0, 0, 0, 110, 100, 90, 84, 78, 71, 65, 58, 51, 45, 39, 32, 26, 20, 12, 0, 0, 0, 0, 0, 0, 118, 110, 103, 93, 86, 80, 75, 70, 65, 59, 53, 47, 40, 31, 23, 15, 4, 0, 0, 0, 0, 126, 119, 112, 104, 95, 89, 83, 78, 72, 66, 60, 54, 47, 39, 32, 25, 17, 12, 1, 0, 0, 134, 127, 120, 114, 103, 97, 91, 85, 78, 72, 66, 60, 54, 47, 41, 35, 29, 23, 16, 10, 1, 144, 137, 130, 124, 113, 107, 101, 95, 88, 82, 76, 70, 64, 57, 51, 45, 39, 33, 26, 15, 1, 152, 145, 138, 132, 123, 117, 111, 105, 98, 92, 86, 80, 74, 67, 61, 55, 49, 43, 36, 20, 1, 162, 155, 148, 142, 133, 127, 121, 115, 108, 102, 96, 90, 84, 77, 71, 65, 59, 53, 46, 30, 1, 172, 165, 158, 152, 143, 137, 131, 125, 118, 112, 106, 100, 94, 87, 81, 75, 69, 63, 56, 45, 20, 200, 200, 200, 200, 200, 200, 200, 200, 198, 193, 188, 183, 178, 173, 168, 163, 158, 153, 148, 129, 104 }; internal static readonly uint[] CELT_PVQ_U_DATA = new uint[1272] { 1u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 3u, 5u, 7u, 9u, 11u, 13u, 15u, 17u, 19u, 21u, 23u, 25u, 27u, 29u, 31u, 33u, 35u, 37u, 39u, 41u, 43u, 45u, 47u, 49u, 51u, 53u, 55u, 57u, 59u, 61u, 63u, 65u, 67u, 69u, 71u, 73u, 75u, 77u, 79u, 81u, 83u, 85u, 87u, 89u, 91u, 93u, 95u, 97u, 99u, 101u, 103u, 105u, 107u, 109u, 111u, 113u, 115u, 117u, 119u, 121u, 123u, 125u, 127u, 129u, 131u, 133u, 135u, 137u, 139u, 141u, 143u, 145u, 147u, 149u, 151u, 153u, 155u, 157u, 159u, 161u, 163u, 165u, 167u, 169u, 171u, 173u, 175u, 177u, 179u, 181u, 183u, 185u, 187u, 189u, 191u, 193u, 195u, 197u, 199u, 201u, 203u, 205u, 207u, 209u, 211u, 213u, 215u, 217u, 219u, 221u, 223u, 225u, 227u, 229u, 231u, 233u, 235u, 237u, 239u, 241u, 243u, 245u, 247u, 249u, 251u, 253u, 255u, 257u, 259u, 261u, 263u, 265u, 267u, 269u, 271u, 273u, 275u, 277u, 279u, 281u, 283u, 285u, 287u, 289u, 291u, 293u, 295u, 297u, 299u, 301u, 303u, 305u, 307u, 309u, 311u, 313u, 315u, 317u, 319u, 321u, 323u, 325u, 327u, 329u, 331u, 333u, 335u, 337u, 339u, 341u, 343u, 345u, 347u, 349u, 351u, 13u, 25u, 41u, 61u, 85u, 113u, 145u, 181u, 221u, 265u, 313u, 365u, 421u, 481u, 545u, 613u, 685u, 761u, 841u, 925u, 1013u, 1105u, 1201u, 1301u, 1405u, 1513u, 1625u, 1741u, 1861u, 1985u, 2113u, 2245u, 2381u, 2521u, 2665u, 2813u, 2965u, 3121u, 3281u, 3445u, 3613u, 3785u, 3961u, 4141u, 4325u, 4513u, 4705u, 4901u, 5101u, 5305u, 5513u, 5725u, 5941u, 6161u, 6385u, 6613u, 6845u, 7081u, 7321u, 7565u, 7813u, 8065u, 8321u, 8581u, 8845u, 9113u, 9385u, 9661u, 9941u, 10225u, 10513u, 10805u, 11101u, 11401u, 11705u, 12013u, 12325u, 12641u, 12961u, 13285u, 13613u, 13945u, 14281u, 14621u, 14965u, 15313u, 15665u, 16021u, 16381u, 16745u, 17113u, 17485u, 17861u, 18241u, 18625u, 19013u, 19405u, 19801u, 20201u, 20605u, 21013u, 21425u, 21841u, 22261u, 22685u, 23113u, 23545u, 23981u, 24421u, 24865u, 25313u, 25765u, 26221u, 26681u, 27145u, 27613u, 28085u, 28561u, 29041u, 29525u, 30013u, 30505u, 31001u, 31501u, 32005u, 32513u, 33025u, 33541u, 34061u, 34585u, 35113u, 35645u, 36181u, 36721u, 37265u, 37813u, 38365u, 38921u, 39481u, 40045u, 40613u, 41185u, 41761u, 42341u, 42925u, 43513u, 44105u, 44701u, 45301u, 45905u, 46513u, 47125u, 47741u, 48361u, 48985u, 49613u, 50245u, 50881u, 51521u, 52165u, 52813u, 53465u, 54121u, 54781u, 55445u, 56113u, 56785u, 57461u, 58141u, 58825u, 59513u, 60205u, 60901u, 61601u, 63u, 129u, 231u, 377u, 575u, 833u, 1159u, 1561u, 2047u, 2625u, 3303u, 4089u, 4991u, 6017u, 7175u, 8473u, 9919u, 11521u, 13287u, 15225u, 17343u, 19649u, 22151u, 24857u, 27775u, 30913u, 34279u, 37881u, 41727u, 45825u, 50183u, 54809u, 59711u, 64897u, 70375u, 76153u, 82239u, 88641u, 95367u, 102425u, 109823u, 117569u, 125671u, 134137u, 142975u, 152193u, 161799u, 171801u, 182207u, 193025u, 204263u, 215929u, 228031u, 240577u, 253575u, 267033u, 280959u, 295361u, 310247u, 325625u, 341503u, 357889u, 374791u, 392217u, 410175u, 428673u, 447719u, 467321u, 487487u, 508225u, 529543u, 551449u, 573951u, 597057u, 620775u, 645113u, 670079u, 695681u, 721927u, 748825u, 776383u, 804609u, 833511u, 863097u, 893375u, 924353u, 956039u, 988441u, 1021567u, 1055425u, 1090023u, 1125369u, 1161471u, 1198337u, 1235975u, 1274393u, 1313599u, 1353601u, 1394407u, 1436025u, 1478463u, 1521729u, 1565831u, 1610777u, 1656575u, 1703233u, 1750759u, 1799161u, 1848447u, 1898625u, 1949703u, 2001689u, 2054591u, 2108417u, 2163175u, 2218873u, 2275519u, 2333121u, 2391687u, 2451225u, 2511743u, 2573249u, 2635751u, 2699257u, 2763775u, 2829313u, 2895879u, 2963481u, 3032127u, 3101825u, 3172583u, 3244409u, 3317311u, 3391297u, 3466375u, 3542553u, 3619839u, 3698241u, 3777767u, 3858425u, 3940223u, 4023169u, 4107271u, 4192537u, 4278975u, 4366593u, 4455399u, 4545401u, 4636607u, 4729025u, 4822663u, 4917529u, 5013631u, 5110977u, 5209575u, 5309433u, 5410559u, 5512961u, 5616647u, 5721625u, 5827903u, 5935489u, 6044391u, 6154617u, 6266175u, 6379073u, 6493319u, 6608921u, 6725887u, 6844225u, 6963943u, 7085049u, 7207551u, 321u, 681u, 1289u, 2241u, 3649u, 5641u, 8361u, 11969u, 16641u, 22569u, 29961u, 39041u, 50049u, 63241u, 78889u, 97281u, 118721u, 143529u, 172041u, 204609u, 241601u, 283401u, 330409u, 383041u, 441729u, 506921u, 579081u, 658689u, 746241u, 842249u, 947241u, 1061761u, 1186369u, 1321641u, 1468169u, 1626561u, 1797441u, 1981449u, 2179241u, 2391489u, 2618881u, 2862121u, 3121929u, 3399041u, 3694209u, 4008201u, 4341801u, 4695809u, 5071041u, 5468329u, 5888521u, 6332481u, 6801089u, 7295241u, 7815849u, 8363841u, 8940161u, 9545769u, 10181641u, 10848769u, 11548161u, 12280841u, 13047849u, 13850241u, 14689089u, 15565481u, 16480521u, 17435329u, 18431041u, 19468809u, 20549801u, 21675201u, 22846209u, 24064041u, 25329929u, 26645121u, 28010881u, 29428489u, 30899241u, 32424449u, 34005441u, 35643561u, 37340169u, 39096641u, 40914369u, 42794761u, 44739241u, 46749249u, 48826241u, 50971689u, 53187081u, 55473921u, 57833729u, 60268041u, 62778409u, 65366401u, 68033601u, 70781609u, 73612041u, 76526529u, 79526721u, 82614281u, 85790889u, 89058241u, 92418049u, 95872041u, 99421961u, 103069569u, 106816641u, 110664969u, 114616361u, 118672641u, 122835649u, 127107241u, 131489289u, 135983681u, 140592321u, 145317129u, 150160041u, 155123009u, 160208001u, 165417001u, 170752009u, 176215041u, 181808129u, 187533321u, 193392681u, 199388289u, 205522241u, 211796649u, 218213641u, 224775361u, 231483969u, 238341641u, 245350569u, 252512961u, 259831041u, 267307049u, 274943241u, 282741889u, 290705281u, 298835721u, 307135529u, 315607041u, 324252609u, 333074601u, 342075401u, 351257409u, 360623041u, 370174729u, 379914921u, 389846081u, 399970689u, 410291241u, 420810249u, 431530241u, 442453761u, 453583369u, 464921641u, 476471169u, 488234561u, 500214441u, 512413449u, 524834241u, 537479489u, 550351881u, 563454121u, 576788929u, 590359041u, 604167209u, 618216201u, 632508801u, 1683u, 3653u, 7183u, 13073u, 22363u, 36365u, 56695u, 85305u, 124515u, 177045u, 246047u, 335137u, 448427u, 590557u, 766727u, 982729u, 1244979u, 1560549u, 1937199u, 2383409u, 2908411u, 3522221u, 4235671u, 5060441u, 6009091u, 7095093u, 8332863u, 9737793u, 11326283u, 13115773u, 15124775u, 17372905u, 19880915u, 22670725u, 25765455u, 29189457u, 32968347u, 37129037u, 41699767u, 46710137u, 52191139u, 58175189u, 64696159u, 71789409u, 79491819u, 87841821u, 96879431u, 106646281u, 117185651u, 128542501u, 140763503u, 153897073u, 167993403u, 183104493u, 199284183u, 216588185u, 235074115u, 254801525u, 275831935u, 298228865u, 322057867u, 347386557u, 374284647u, 402823977u, 433078547u, 465124549u, 499040399u, 534906769u, 572806619u, 612825229u, 655050231u, 699571641u, 746481891u, 795875861u, 847850911u, 902506913u, 959946283u, 1020274013u, 1083597703u, 1150027593u, 1219676595u, 1292660325u, 1369097135u, 1449108145u, 1532817275u, 1620351277u, 1711839767u, 1807415257u, 1907213187u, 2011371957u, 2120032959u, 8989u, 19825u, 40081u, 75517u, 134245u, 227305u, 369305u, 579125u, 880685u, 1303777u, 1884961u, 2668525u, 3707509u, 5064793u, 6814249u, 9041957u, 11847485u, 15345233u, 19665841u, 24957661u, 31388293u, 39146185u, 48442297u, 59511829u, 72616013u, 88043969u, 106114625u, 127178701u, 151620757u, 179861305u, 212358985u, 249612805u, 292164445u, 340600625u, 395555537u, 457713341u, 527810725u, 606639529u, 695049433u, 793950709u, 904317037u, 1027188385u, 1163673953u, 1314955181u, 1482288821u, 1667010073u, 1870535785u, 2094367717u, 48639u, 108545u, 224143u, 433905u, 795455u, 1392065u, 2340495u, 3800305u, 5984767u, 9173505u, 13726991u, 20103025u, 28875327u, 40754369u, 56610575u, 77500017u, 104692735u, 139703809u, 184327311u, 240673265u, 311207743u, 398796225u, 506750351u, 638878193u, 799538175u, 993696769u, 1226990095u, 1505789553u, 1837271615u, 2229491905u, 265729u, 598417u, 1256465u, 2485825u, 4673345u, 8405905u, 14546705u, 24331777u, 39490049u, 62390545u, 96220561u, 145198913u, 214828609u, 312193553u, 446304145u, 628496897u, 872893441u, 1196924561u, 1621925137u, 2173806145u, 1462563u, 3317445u, 7059735u, 14218905u, 27298155u, 50250765u, 89129247u, 152951073u, 254831667u, 413442773u, 654862247u, 1014889769u, 1541911931u, 2300409629u, 3375210671u, 8097453u, 18474633u, 39753273u, 81270333u, 158819253u, 298199265u, 540279585u, 948062325u, 1616336765u, 45046719u, 103274625u, 224298231u, 464387817u, 921406335u, 1759885185u, 3248227095u, 251595969u, 579168825u, 1267854873u, 2653649025u, 1409933619u }; internal static readonly int[] window120 = new int[120] { 2, 20, 55, 108, 178, 266, 372, 494, 635, 792, 966, 1157, 1365, 1590, 1831, 2089, 2362, 2651, 2956, 3276, 3611, 3961, 4325, 4703, 5094, 5499, 5916, 6346, 6788, 7241, 7705, 8179, 8663, 9156, 9657, 10167, 10684, 11207, 11736, 12271, 12810, 13353, 13899, 14447, 14997, 15547, 16098, 16648, 17197, 17744, 18287, 18827, 19363, 19893, 20418, 20936, 21447, 21950, 22445, 22931, 23407, 23874, 24330, 24774, 25208, 25629, 26039, 26435, 26819, 27190, 27548, 27893, 28224, 28541, 28845, 29135, 29411, 29674, 29924, 30160, 30384, 30594, 30792, 30977, 31151, 31313, 31463, 31602, 31731, 31849, 31958, 32057, 32148, 32229, 32303, 32370, 32429, 32481, 32528, 32568, 32604, 32634, 32661, 32683, 32701, 32717, 32729, 32740, 32748, 32754, 32758, 32762, 32764, 32766, 32767, 32767, 32767, 32767, 32767, 32767 }; internal static readonly short[] logN400 = new short[21] { 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36 }; internal static readonly short[] cache_index50 = new short[105] { -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41, 82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41, 41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41, 41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305, 318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240, 305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240, 240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387 }; internal static readonly byte[] cache_bits50 = new byte[392] { 40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28, 31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50, 51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65, 66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61, 64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92, 94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123, 124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94, 97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139, 142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35, 28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149, 153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225, 229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157, 166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63, 86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250, 25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180, 185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89, 110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41, 74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138, 163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214, 228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49, 90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47, 87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57, 106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187, 224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127, 182, 234 }; internal static readonly byte[] cache_caps50 = new byte[168] { 224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185, 178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240, 240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160, 160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172, 138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207, 204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185, 185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39, 207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201, 188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204, 204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175, 140, 66, 40 }; internal static readonly short[] fft_twiddles48000_960 = new short[960] { 32767, 0, 32766, -429, 32757, -858, 32743, -1287, 32724, -1715, 32698, -2143, 32667, -2570, 32631, -2998, 32588, -3425, 32541, -3851, 32488, -4277, 32429, -4701, 32364, -5125, 32295, -5548, 32219, -5971, 32138, -6393, 32051, -6813, 31960, -7231, 31863, -7650, 31760, -8067, 31652, -8481, 31539, -8895, 31419, -9306, 31294, -9716, 31165, -10126, 31030, -10532, 30889, -10937, 30743, -11340, 30592, -11741, 30436, -12141, 30274, -12540, 30107, -12935, 29936, -13328, 29758, -13718, 29577, -14107, 29390, -14493, 29197, -14875, 29000, -15257, 28797, -15635, 28590, -16010, 28379, -16384, 28162, -16753, 27940, -17119, 27714, -17484, 27482, -17845, 27246, -18205, 27006, -18560, 26760, -18911, 26510, -19260, 26257, -19606, 25997, -19947, 25734, -20286, 25466, -20621, 25194, -20952, 24918, -21281, 24637, -21605, 24353, -21926, 24063, -22242, 23770, -22555, 23473, -22865, 23171, -23171, 22866, -23472, 22557, -23769, 22244, -24063, 21927, -24352, 21606, -24636, 21282, -24917, 20954, -25194, 20622, -25465, 20288, -25733, 19949, -25997, 19607, -26255, 19261, -26509, 18914, -26760, 18561, -27004, 18205, -27246, 17846, -27481, 17485, -27713, 17122, -27940, 16755, -28162, 16385, -28378, 16012, -28590, 15636, -28797, 15258, -28999, 14878, -29197, 14494, -29389, 14108, -29576, 13720, -29757, 13329, -29934, 12937, -30107, 12540, -30274, 12142, -30435, 11744, -30592, 11342, -30743, 10939, -30889, 10534, -31030, 10127, -31164, 9718, -31294, 9307, -31418, 8895, -31537, 8482, -31652, 8067, -31759, 7650, -31862, 7233, -31960, 6815, -32051, 6393, -32138, 5973, -32219, 5549, -32294, 5127, -32364, 4703, -32429, 4278, -32487, 3852, -32541, 3426, -32588, 2999, -32630, 2572, -32667, 2144, -32698, 1716, -32724, 1287, -32742, 860, -32757, 430, -32766, 0, -32767, -429, -32766, -858, -32757, -1287, -32743, -1715, -32724, -2143, -32698, -2570, -32667, -2998, -32631, -3425, -32588, -3851, -32541, -4277, -32488, -4701, -32429, -5125, -32364, -5548, -32295, -5971, -32219, -6393, -32138, -6813, -32051, -7231, -31960, -7650, -31863, -8067, -31760, -8481, -31652, -8895, -31539, -9306, -31419, -9716, -31294, -10126, -31165, -10532, -31030, -10937, -30889, -11340, -30743, -11741, -30592, -12141, -30436, -12540, -30274, -12935, -30107, -13328, -29936, -13718, -29758, -14107, -29577, -14493, -29390, -14875, -29197, -15257, -29000, -15635, -28797, -16010, -28590, -16384, -28379, -16753, -28162, -17119, -27940, -17484, -27714, -17845, -27482, -18205, -27246, -18560, -27006, -18911, -26760, -19260, -26510, -19606, -26257, -19947, -25997, -20286, -25734, -20621, -25466, -20952, -25194, -21281, -24918, -21605, -24637, -21926, -24353, -22242, -24063, -22555, -23770, -22865, -23473, -23171, -23171, -23472, -22866, -23769, -22557, -24063, -22244, -24352, -21927, -24636, -21606, -24917, -21282, -25194, -20954, -25465, -20622, -25733, -20288, -25997, -19949, -26255, -19607, -26509, -19261, -26760, -18914, -27004, -18561, -27246, -18205, -27481, -17846, -27713, -17485, -27940, -17122, -28162, -16755, -28378, -16385, -28590, -16012, -28797, -15636, -28999, -15258, -29197, -14878, -29389, -14494, -29576, -14108, -29757, -13720, -29934, -13329, -30107, -12937, -30274, -12540, -30435, -12142, -30592, -11744, -30743, -11342, -30889, -10939, -31030, -10534, -31164, -10127, -31294, -9718, -31418, -9307, -31537, -8895, -31652, -8482, -31759, -8067, -31862, -7650, -31960, -7233, -32051, -6815, -32138, -6393, -32219, -5973, -32294, -5549, -32364, -5127, -32429, -4703, -32487, -4278, -32541, -3852, -32588, -3426, -32630, -2999, -32667, -2572, -32698, -2144, -32724, -1716, -32742, -1287, -32757, -860, -32766, -430, -32767, 0, -32766, 429, -32757, 858, -32743, 1287, -32724, 1715, -32698, 2143, -32667, 2570, -32631, 2998, -32588, 3425, -32541, 3851, -32488, 4277, -32429, 4701, -32364, 5125, -32295, 5548, -32219, 5971, -32138, 6393, -32051, 6813, -31960, 7231, -31863, 7650, -31760, 8067, -31652, 8481, -31539, 8895, -31419, 9306, -31294, 9716, -31165, 10126, -31030, 10532, -30889, 10937, -30743, 11340, -30592, 11741, -30436, 12141, -30274, 12540, -30107, 12935, -29936, 13328, -29758, 13718, -29577, 14107, -29390, 14493, -29197, 14875, -29000, 15257, -28797, 15635, -28590, 16010, -28379, 16384, -28162, 16753, -27940, 17119, -27714, 17484, -27482, 17845, -27246, 18205, -27006, 18560, -26760, 18911, -26510, 19260, -26257, 19606, -25997, 19947, -25734, 20286, -25466, 20621, -25194, 20952, -24918, 21281, -24637, 21605, -24353, 21926, -24063, 22242, -23770, 22555, -23473, 22865, -23171, 23171, -22866, 23472, -22557, 23769, -22244, 24063, -21927, 24352, -21606, 24636, -21282, 24917, -20954, 25194, -20622, 25465, -20288, 25733, -19949, 25997, -19607, 26255, -19261, 26509, -18914, 26760, -18561, 27004, -18205, 27246, -17846, 27481, -17485, 27713, -17122, 27940, -16755, 28162, -16385, 28378, -16012, 28590, -15636, 28797, -15258, 28999, -14878, 29197, -14494, 29389, -14108, 29576, -13720, 29757, -13329, 29934, -12937, 30107, -12540, 30274, -12142, 30435, -11744, 30592, -11342, 30743, -10939, 30889, -10534, 31030, -10127, 31164, -9718, 31294, -9307, 31418, -8895, 31537, -8482, 31652, -8067, 31759, -7650, 31862, -7233, 31960, -6815, 32051, -6393, 32138, -5973, 32219, -5549, 32294, -5127, 32364, -4703, 32429, -4278, 32487, -3852, 32541, -3426, 32588, -2999, 32630, -2572, 32667, -2144, 32698, -1716, 32724, -1287, 32742, -860, 32757, -430, 32766, 0, 32767, 429, 32766, 858, 32757, 1287, 32743, 1715, 32724, 2143, 32698, 2570, 32667, 2998, 32631, 3425, 32588, 3851, 32541, 4277, 32488, 4701, 32429, 5125, 32364, 5548, 32295, 5971, 32219, 6393, 32138, 6813, 32051, 7231, 31960, 7650, 31863, 8067, 31760, 8481, 31652, 8895, 31539, 9306, 31419, 9716, 31294, 10126, 31165, 10532, 31030, 10937, 30889, 11340, 30743, 11741, 30592, 12141, 30436, 12540, 30274, 12935, 30107, 13328, 29936, 13718, 29758, 14107, 29577, 14493, 29390, 14875, 29197, 15257, 29000, 15635, 28797, 16010, 28590, 16384, 28379, 16753, 28162, 17119, 27940, 17484, 27714, 17845, 27482, 18205, 27246, 18560, 27006, 18911, 26760, 19260, 26510, 19606, 26257, 19947, 25997, 20286, 25734, 20621, 25466, 20952, 25194, 21281, 24918, 21605, 24637, 21926, 24353, 22242, 24063, 22555, 23770, 22865, 23473, 23171, 23171, 23472, 22866, 23769, 22557, 24063, 22244, 24352, 21927, 24636, 21606, 24917, 21282, 25194, 20954, 25465, 20622, 25733, 20288, 25997, 19949, 26255, 19607, 26509, 19261, 26760, 18914, 27004, 18561, 27246, 18205, 27481, 17846, 27713, 17485, 27940, 17122, 28162, 16755, 28378, 16385, 28590, 16012, 28797, 15636, 28999, 15258, 29197, 14878, 29389, 14494, 29576, 14108, 29757, 13720, 29934, 13329, 30107, 12937, 30274, 12540, 30435, 12142, 30592, 11744, 30743, 11342, 30889, 10939, 31030, 10534, 31164, 10127, 31294, 9718, 31418, 9307, 31537, 8895, 31652, 8482, 31759, 8067, 31862, 7650, 31960, 7233, 32051, 6815, 32138, 6393, 32219, 5973, 32294, 5549, 32364, 5127, 32429, 4703, 32487, 4278, 32541, 3852, 32588, 3426, 32630, 2999, 32667, 2572, 32698, 2144, 32724, 1716, 32742, 1287, 32757, 860, 32766, 430 }; internal static readonly short[] fft_bitrev480 = new short[480] { 0, 96, 192, 288, 384, 32, 128, 224, 320, 416, 64, 160, 256, 352, 448, 8, 104, 200, 296, 392, 40, 136, 232, 328, 424, 72, 168, 264, 360, 456, 16, 112, 208, 304, 400, 48, 144, 240, 336, 432, 80, 176, 272, 368, 464, 24, 120, 216, 312, 408, 56, 152, 248, 344, 440, 88, 184, 280, 376, 472, 4, 100, 196, 292, 388, 36, 132, 228, 324, 420, 68, 164, 260, 356, 452, 12, 108, 204, 300, 396, 44, 140, 236, 332, 428, 76, 172, 268, 364, 460, 20, 116, 212, 308, 404, 52, 148, 244, 340, 436, 84, 180, 276, 372, 468, 28, 124, 220, 316, 412, 60, 156, 252, 348, 444, 92, 188, 284, 380, 476, 1, 97, 193, 289, 385, 33, 129, 225, 321, 417, 65, 161, 257, 353, 449, 9, 105, 201, 297, 393, 41, 137, 233, 329, 425, 73, 169, 265, 361, 457, 17, 113, 209, 305, 401, 49, 145, 241, 337, 433, 81, 177, 273, 369, 465, 25, 121, 217, 313, 409, 57, 153, 249, 345, 441, 89, 185, 281, 377, 473, 5, 101, 197, 293, 389, 37, 133, 229, 325, 421, 69, 165, 261, 357, 453, 13, 109, 205, 301, 397, 45, 141, 237, 333, 429, 77, 173, 269, 365, 461, 21, 117, 213, 309, 405, 53, 149, 245, 341, 437, 85, 181, 277, 373, 469, 29, 125, 221, 317, 413, 61, 157, 253, 349, 445, 93, 189, 285, 381, 477, 2, 98, 194, 290, 386, 34, 130, 226, 322, 418, 66, 162, 258, 354, 450, 10, 106, 202, 298, 394, 42, 138, 234, 330, 426, 74, 170, 266, 362, 458, 18, 114, 210, 306, 402, 50, 146, 242, 338, 434, 82, 178, 274, 370, 466, 26, 122, 218, 314, 410, 58, 154, 250, 346, 442, 90, 186, 282, 378, 474, 6, 102, 198, 294, 390, 38, 134, 230, 326, 422, 70, 166, 262, 358, 454, 14, 110, 206, 302, 398, 46, 142, 238, 334, 430, 78, 174, 270, 366, 462, 22, 118, 214, 310, 406, 54, 150, 246, 342, 438, 86, 182, 278, 374, 470, 30, 126, 222, 318, 414, 62, 158, 254, 350, 446, 94, 190, 286, 382, 478, 3, 99, 195, 291, 387, 35, 131, 227, 323, 419, 67, 163, 259, 355, 451, 11, 107, 203, 299, 395, 43, 139, 235, 331, 427, 75, 171, 267, 363, 459, 19, 115, 211, 307, 403, 51, 147, 243, 339, 435, 83, 179, 275, 371, 467, 27, 123, 219, 315, 411, 59, 155, 251, 347, 443, 91, 187, 283, 379, 475, 7, 103, 199, 295, 391, 39, 135, 231, 327, 423, 71, 167, 263, 359, 455, 15, 111, 207, 303, 399, 47, 143, 239, 335, 431, 79, 175, 271, 367, 463, 23, 119, 215, 311, 407, 55, 151, 247, 343, 439, 87, 183, 279, 375, 471, 31, 127, 223, 319, 415, 63, 159, 255, 351, 447, 95, 191, 287, 383, 479 }; internal static readonly short[] fft_bitrev240 = new short[240] { 0, 48, 96, 144, 192, 16, 64, 112, 160, 208, 32, 80, 128, 176, 224, 4, 52, 100, 148, 196, 20, 68, 116, 164, 212, 36, 84, 132, 180, 228, 8, 56, 104, 152, 200, 24, 72, 120, 168, 216, 40, 88, 136, 184, 232, 12, 60, 108, 156, 204, 28, 76, 124, 172, 220, 44, 92, 140, 188, 236, 1, 49, 97, 145, 193, 17, 65, 113, 161, 209, 33, 81, 129, 177, 225, 5, 53, 101, 149, 197, 21, 69, 117, 165, 213, 37, 85, 133, 181, 229, 9, 57, 105, 153, 201, 25, 73, 121, 169, 217, 41, 89, 137, 185, 233, 13, 61, 109, 157, 205, 29, 77, 125, 173, 221, 45, 93, 141, 189, 237, 2, 50, 98, 146, 194, 18, 66, 114, 162, 210, 34, 82, 130, 178, 226, 6, 54, 102, 150, 198, 22, 70, 118, 166, 214, 38, 86, 134, 182, 230, 10, 58, 106, 154, 202, 26, 74, 122, 170, 218, 42, 90, 138, 186, 234, 14, 62, 110, 158, 206, 30, 78, 126, 174, 222, 46, 94, 142, 190, 238, 3, 51, 99, 147, 195, 19, 67, 115, 163, 211, 35, 83, 131, 179, 227, 7, 55, 103, 151, 199, 23, 71, 119, 167, 215, 39, 87, 135, 183, 231, 11, 59, 107, 155, 203, 27, 75, 123, 171, 219, 43, 91, 139, 187, 235, 15, 63, 111, 159, 207, 31, 79, 127, 175, 223, 47, 95, 143, 191, 239 }; internal static readonly short[] fft_bitrev120 = new short[120] { 0, 24, 48, 72, 96, 8, 32, 56, 80, 104, 16, 40, 64, 88, 112, 4, 28, 52, 76, 100, 12, 36, 60, 84, 108, 20, 44, 68, 92, 116, 1, 25, 49, 73, 97, 9, 33, 57, 81, 105, 17, 41, 65, 89, 113, 5, 29, 53, 77, 101, 13, 37, 61, 85, 109, 21, 45, 69, 93, 117, 2, 26, 50, 74, 98, 10, 34, 58, 82, 106, 18, 42, 66, 90, 114, 6, 30, 54, 78, 102, 14, 38, 62, 86, 110, 22, 46, 70, 94, 118, 3, 27, 51, 75, 99, 11, 35, 59, 83, 107, 19, 43, 67, 91, 115, 7, 31, 55, 79, 103, 15, 39, 63, 87, 111, 23, 47, 71, 95, 119 }; internal static readonly short[] fft_bitrev60 = new short[60] { 0, 12, 24, 36, 48, 4, 16, 28, 40, 52, 8, 20, 32, 44, 56, 1, 13, 25, 37, 49, 5, 17, 29, 41, 53, 9, 21, 33, 45, 57, 2, 14, 26, 38, 50, 6, 18, 30, 42, 54, 10, 22, 34, 46, 58, 3, 15, 27, 39, 51, 7, 19, 31, 43, 55, 11, 23, 35, 47, 59 }; internal static readonly FFTState fft_state48000_960_0 = new FFTState { nfft = 480, scale = 17476, scale_shift = 8, shift = -1, factors = new short[16] { 5, 96, 3, 32, 4, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0 }, bitrev = fft_bitrev480, twiddles = fft_twiddles48000_960 }; internal static readonly FFTState fft_state48000_960_1 = new FFTState { nfft = 240, scale = 17476, scale_shift = 7, shift = 1, factors = new short[16] { 5, 48, 3, 16, 4, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, bitrev = fft_bitrev240, twiddles = fft_twiddles48000_960 }; internal static readonly FFTState fft_state48000_960_2 = new FFTState { nfft = 120, scale = 17476, scale_shift = 6, shift = 2, factors = new short[16] { 5, 24, 3, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, bitrev = fft_bitrev120, twiddles = fft_twiddles48000_960 }; internal static readonly FFTState fft_state48000_960_3 = new FFTState { nfft = 60, scale = 17476, scale_shift = 5, shift = 3, factors = new short[16] { 5, 12, 3, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, bitrev = fft_bitrev60, twiddles = fft_twiddles48000_960 }; internal static readonly short[] mdct_twiddles960 = new short[1800] { 32767, 32767, 32767, 32766, 32765, 32763, 32761, 32759, 32756, 32753, 32750, 32746, 32742, 32738, 32733, 32728, 32722, 32717, 32710, 32704, 32697, 32690, 32682, 32674, 32666, 32657, 32648, 32639, 32629, 32619, 32609, 32598, 32587, 32576, 32564, 32552, 32539, 32526, 32513, 32500, 32486, 32472, 32457, 32442, 32427, 32411, 32395, 32379, 32362, 32345, 32328, 32310, 32292, 32274, 32255, 32236, 32217, 32197, 32177, 32157, 32136, 32115, 32093, 32071, 32049, 32027, 32004, 31981, 31957, 31933, 31909, 31884, 31859, 31834, 31809, 31783, 31756, 31730, 31703, 31676, 31648, 31620, 31592, 31563, 31534, 31505, 31475, 31445, 31415, 31384, 31353, 31322, 31290, 31258, 31226, 31193, 31160, 31127, 31093, 31059, 31025, 30990, 30955, 30920, 30884, 30848, 30812, 30775, 30738, 30701, 30663, 30625, 30587, 30548, 30509, 30470, 30430, 30390, 30350, 30309, 30269, 30227, 30186, 30144, 30102, 30059, 30016, 29973, 29930, 29886, 29842, 29797, 29752, 29707, 29662, 29616, 29570, 29524, 29477, 29430, 29383, 29335, 29287, 29239, 29190, 29142, 29092, 29043, 28993, 28943, 28892, 28842, 28791, 28739, 28688, 28636, 28583, 28531, 28478, 28425, 28371, 28317, 28263, 28209, 28154, 28099, 28044, 27988, 27932, 27876, 27820, 27763, 27706, 27648, 27591, 27533, 27474, 27416, 27357, 27298, 27238, 27178, 27118, 27058, 26997, 26936, 26875, 26814, 26752, 26690, 26628, 26565, 26502, 26439, 26375, 26312, 26247, 26183, 26119, 26054, 25988, 25923, 25857, 25791, 25725, 25658, 25592, 25524, 25457, 25389, 25322, 25253, 25185, 25116, 25047, 24978, 24908, 24838, 24768, 24698, 24627, 24557, 24485, 24414, 24342, 24270, 24198, 24126, 24053, 23980, 23907, 23834, 23760, 23686, 23612, 23537, 23462, 23387, 23312, 23237, 23161, 23085, 23009, 22932, 22856, 22779, 22701, 22624, 22546, 22468, 22390, 22312, 22233, 22154, 22075, 21996, 21916, 21836, 21756, 21676, 21595, 21515, 21434, 21352, 21271, 21189, 21107, 21025, 20943, 20860, 20777, 20694, 20611, 20528, 20444, 20360, 20276, 20192, 20107, 20022, 19937, 19852, 19767, 19681, 19595, 19509, 19423, 19336, 19250, 19163, 19076, 18988, 18901, 18813, 18725, 18637, 18549, 18460, 18372, 18283, 18194, 18104, 18015, 17925, 17835, 17745, 17655, 17565, 17474, 17383, 17292, 17201, 17110, 17018, 16927, 16835, 16743, 16650, 16558, 16465, 16372, 16279, 16186, 16093, 15999, 15906, 15812, 15718, 15624, 15529, 15435, 15340, 15245, 15150, 15055, 14960, 14864, 14769, 14673, 14577, 14481, 14385, 14288, 14192, 14095, 13998, 13901, 13804, 13706, 13609, 13511, 13414, 13316, 13218, 13119, 13021, 12923, 12824, 12725, 12626, 12527, 12428, 12329, 12230, 12130, 12030, 11930, 11831, 11730, 11630, 11530, 11430, 11329, 11228, 11128, 11027, 10926, 10824, 10723, 10622, 10520, 10419, 10317, 10215, 10113, 10011, 9909, 9807, 9704, 9602, 9499, 9397, 9294, 9191, 9088, 8985, 8882, 8778, 8675, 8572, 8468, 8364, 8261, 8157, 8053, 7949, 7845, 7741, 7637, 7532, 7428, 7323, 7219, 7114, 7009, 6905, 6800, 6695, 6590, 6485, 6380, 6274, 6169, 6064, 5958, 5853, 5747, 5642, 5536, 5430, 5325, 5219, 5113, 5007, 4901, 4795, 4689, 4583, 4476, 4370, 4264, 4157, 4051, 3945, 3838, 3732, 3625, 3518, 3412, 3305, 3198, 3092, 2985, 2878, 2771, 2664, 2558, 2451, 2344, 2237, 2130, 2023, 1916, 1809, 1702, 1594, 1487, 1380, 1273, 1166, 1059, 952, 844, 737, 630, 523, 416, 308, 201, 94, -13, -121, -228, -335, -442, -550, -657, -764, -871, -978, -1086, -1193, -1300, -1407, -1514, -1621, -1728, -1835, -1942, -2049, -2157, -2263, -2370, -2477, -2584, -2691, -2798, -2905, -3012, -3118, -3225, -3332, -3439, -3545, -3652, -3758, -3865, -3971, -4078, -4184, -4290, -4397, -4503, -4609, -4715, -4821, -4927, -5033, -5139, -5245, -5351, -5457, -5562, -5668, -5774, -5879, -5985, -6090, -6195, -6301, -6406, -6511, -6616, -6721, -6826, -6931, -7036, -7140, -7245, -7349, -7454, -7558, -7663, -7767, -7871, -7975, -8079, -8183, -8287, -8390, -8494, -8597, -8701, -8804, -8907, -9011, -9114, -9217, -9319, -9422, -9525, -9627, -9730, -9832, -9934, -10037, -10139, -10241, -10342, -10444, -10546, -10647, -10748, -10850, -10951, -11052, -11153, -11253, -11354, -11455, -11555, -11655, -11756, -11856, -11955, -12055, -12155, -12254, -12354, -12453, -12552, -12651, -12750, -12849, -12947, -13046, -13144, -13242, -13340, -13438, -13536, -13633, -13731, -13828, -13925, -14022, -14119, -14216, -14312, -14409, -14505, -14601, -14697, -14793, -14888, -14984, -15079, -15174, -15269, -15364, -15459, -15553, -15647, -15741, -15835, -15929, -16023, -16116, -16210, -16303, -16396, -16488, -16581, -16673, -16766, -16858, -16949, -17041, -17133, -17224, -17315, -17406, -17497, -17587, -17678, -17768, -17858, -17948, -18037, -18127, -18216, -18305, -18394, -18483, -18571, -18659, -18747, -18835, -18923, -19010, -19098, -19185, -19271, -19358, -19444, -19531, -19617, -19702, -19788, -19873, -19959, -20043, -20128, -20213, -20297, -20381, -20465, -20549, -20632, -20715, -20798, -20881, -20963, -21046, -21128, -21210, -21291, -21373, -21454, -21535, -21616, -21696, -21776, -21856, -21936, -22016, -22095, -22174, -22253, -22331, -22410, -22488, -22566, -22643, -22721, -22798, -22875, -22951, -23028, -23104, -23180, -23256, -23331, -23406, -23481, -23556, -23630, -23704, -23778, -23852, -23925, -23998, -24071, -24144, -24216, -24288, -24360, -24432, -24503, -24574, -24645, -24716, -24786, -24856, -24926, -24995, -25064, -25133, -25202, -25270, -25339, -25406, -25474, -25541, -25608, -25675, -25742, -25808, -25874, -25939, -26005, -26070, -26135, -26199, -26264, -26327, -26391, -26455, -26518, -26581, -26643, -26705, -26767, -26829, -26891, -26952, -27013, -27073, -27133, -27193, -27253, -27312, -27372, -27430, -27489, -27547, -27605, -27663, -27720, -27777, -27834, -27890, -27946, -28002, -28058, -28113, -28168, -28223, -28277, -28331, -28385, -28438, -28491, -28544, -28596, -28649, -28701, -28752, -28803, -28854, -28905, -28955, -29006, -29055, -29105, -29154, -29203, -29251, -29299, -29347, -29395, -29442, -29489, -29535, -29582, -29628, -29673, -29719, -29764, -29808, -29853, -29897, -29941, -29984, -30027, -30070, -30112, -30154, -30196, -30238, -30279, -30320, -30360, -30400, -30440, -30480, -30519, -30558, -30596, -30635, -30672, -30710, -30747, -30784, -30821, -30857, -30893, -30929, -30964, -30999, -31033, -31068, -31102, -31135, -31168, -31201, -31234, -31266, -31298, -31330, -31361, -31392, -31422, -31453, -31483, -31512, -31541, -31570, -31599, -31627, -31655, -31682, -31710, -31737, -31763, -31789, -31815, -31841, -31866, -31891, -31915, -31939, -31963, -31986, -32010, -32032, -32055, -32077, -32099, -32120, -32141, -32162, -32182, -32202, -32222, -32241, -32260, -32279, -32297, -32315, -32333, -32350, -32367, -32383, -32399, -32415, -32431, -32446, -32461, -32475, -32489, -32503, -32517, -32530, -32542, -32555, -32567, -32579, -32590, -32601, -32612, -32622, -32632, -32641, -32651, -32659, -32668, -32676, -32684, -32692, -32699, -32706, -32712, -32718, -32724, -32729, -32734, -32739, -32743, -32747, -32751, -32754, -32757, -32760, -32762, -32764, -32765, -32767, -32767, -32767, 32767, 32767, 32765, 32761, 32756, 32750, 32742, 32732, 32722, 32710, 32696, 32681, 32665, 32647, 32628, 32608, 32586, 32562, 32538, 32512, 32484, 32455, 32425, 32393, 32360, 32326, 32290, 32253, 32214, 32174, 32133, 32090, 32046, 32001, 31954, 31906, 31856, 31805, 31753, 31700, 31645, 31588, 31530, 31471, 31411, 31349, 31286, 31222, 31156, 31089, 31020, 30951, 30880, 30807, 30733, 30658, 30582, 30504, 30425, 30345, 30263, 30181, 30096, 30011, 29924, 29836, 29747, 29656, 29564, 29471, 29377, 29281, 29184, 29086, 28987, 28886, 28784, 28681, 28577, 28471, 28365, 28257, 28147, 28037, 27925, 27812, 27698, 27583, 27467, 27349, 27231, 27111, 26990, 26868, 26744, 26620, 26494, 26367, 26239, 26110, 25980, 25849, 25717, 25583, 25449, 25313, 25176, 25038, 24900, 24760, 24619, 24477, 24333, 24189, 24044, 23898, 23751, 23602, 23453, 23303, 23152, 22999, 22846, 22692, 22537, 22380, 22223, 22065, 21906, 21746, 21585, 21423, 21261, 21097, 20933, 20767, 20601, 20434, 20265, 20096, 19927, 19756, 19584, 19412, 19239, 19065, 18890, 18714, 18538, 18361, 18183, 18004, 17824, 17644, 17463, 17281, 17098, 16915, 16731, 16546, 16361, 16175, 15988, 15800, 15612, 15423, 15234, 15043, 14852, 14661, 14469, 14276, 14083, 13889, 13694, 13499, 13303, 13107, 12910, 12713, 12515, 12317, 12118, 11918, 11718, 11517, 11316, 11115, 10913, 10710, 10508, 10304, 10100, 9896, 9691, 9486, 9281, 9075, 8869, 8662, 8455, 8248, 8040, 7832, 7623, 7415, 7206, 6996, 6787, 6577, 6366, 6156, 5945, 5734, 5523, 5311, 5100, 4888, 4675, 4463, 4251, 4038, 3825, 3612, 3399, 3185, 2972, 2758, 2544, 2330, 2116, 1902, 1688, 1474, 1260, 1045, 831, 617, 402, 188, -27, -241, -456, -670, -885, -1099, -1313, -1528, -1742, -1956, -2170, -2384, -2598, -2811, -3025, -3239, -3452, -3665, -3878, -4091, -4304, -4516, -4728, -4941, -5153, -5364, -5576, -5787, -5998, -6209, -6419, -6629, -6839, -7049, -7258, -7467, -7676, -7884, -8092, -8300, -8507, -8714, -8920, -9127, -9332, -9538, -9743, -9947, -10151, -10355, -10558, -10761, -10963, -11165, -11367, -11568, -11768, -11968, -12167, -12366, -12565, -12762, -12960, -13156, -13352, -13548, -13743, -13937, -14131, -14324, -14517, -14709, -14900, -15091, -15281, -15470, -15659, -15847, -16035, -16221, -16407, -16593, -16777, -16961, -17144, -17326, -17508, -17689, -17869, -18049, -18227, -18405, -18582, -18758, -18934, -19108, -19282, -19455, -19627, -19799, -19969, -20139, -20308, -20475, -20642, -20809, -20974, -21138, -21301, -21464, -21626, -21786, -21946, -22105, -22263, -22420, -22575, -22730, -22884, -23037, -23189, -23340, -23490, -23640, -23788, -23935, -24080, -24225, -24369, -24512, -24654, -24795, -24934, -25073, -25211, -25347, -25482, -25617, -25750, -25882, -26013, -26143, -26272, -26399, -26526, -26651, -26775, -26898, -27020, -27141, -27260, -27379, -27496, -27612, -27727, -27841, -27953, -28065, -28175, -28284, -28391, -28498, -28603, -28707, -28810, -28911, -29012, -29111, -29209, -29305, -29401, -29495, -29587, -29679, -29769, -29858, -29946, -30032, -30118, -30201, -30284, -30365, -30445, -30524, -30601, -30677, -30752, -30825, -30897, -30968, -31038, -31106, -31172, -31238, -31302, -31365, -31426, -31486, -31545, -31602, -31658, -31713, -31766, -31818, -31869, -31918, -31966, -32012, -32058, -32101, -32144, -32185, -32224, -32262, -32299, -32335, -32369, -32401, -32433, -32463, -32491, -32518, -32544, -32568, -32591, -32613, -32633, -32652, -32669, -32685, -32700, -32713, -32724, -32735, -32744, -32751, -32757, -32762, -32766, -32767, 32767, 32764, 32755, 32741, 32720, 32694, 32663, 32626, 32583, 32535, 32481, 32421, 32356, 32286, 32209, 32128, 32041, 31948, 31850, 31747, 31638, 31523, 31403, 31278, 31148, 31012, 30871, 30724, 30572, 30415, 30253, 30086, 29913, 29736, 29553, 29365, 29172, 28974, 28771, 28564, 28351, 28134, 27911, 27684, 27452, 27216, 26975, 26729, 26478, 26223, 25964, 25700, 25432, 25159, 24882, 24601, 24315, 24026, 23732, 23434, 23133, 22827, 22517, 22204, 21886, 21565, 21240, 20912, 20580, 20244, 19905, 19563, 19217, 18868, 18516, 18160, 17802, 17440, 17075, 16708, 16338, 15964, 15588, 15210, 14829, 14445, 14059, 13670, 13279, 12886, 12490, 12093, 11693, 11291, 10888, 10482, 10075, 9666, 9255, 8843, 8429, 8014, 7597, 7180, 6760, 6340, 5919, 5496, 5073, 4649, 4224, 3798, 3372, 2945, 2517, 2090, 1661, 1233, 804, 375, -54, -483, -911, -1340, -1768, -2197, -2624, -3052, -3479, -3905, -4330, -4755, -5179, -5602, -6024, -6445, -6865, -7284, -7702, -8118, -8533, -8946, -9358, -9768, -10177, -10584, -10989, -11392, -11793, -12192, -12589, -12984, -13377, -13767, -14155, -14541, -14924, -15305, -15683, -16058, -16430, -16800, -17167, -17531, -17892, -18249, -18604, -18956, -19304, -19649, -19990, -20329, -20663, -20994, -21322, -21646, -21966, -22282, -22595, -22904, -23208, -23509, -23806, -24099, -24387, -24672, -24952, -25228, -25499, -25766, -26029, -26288, -26541, -26791, -27035, -27275, -27511, -27741, -27967, -28188, -28405, -28616, -28823, -29024, -29221, -29412, -29599, -29780, -29957, -30128, -30294, -30455, -30611, -30761, -30906, -31046, -31181, -31310, -31434, -31552, -31665, -31773, -31875, -31972, -32063, -32149, -32229, -32304, -32373, -32437, -32495, -32547, -32594, -32635, -32671, -32701, -32726, -32745, -32758, -32766, 32767, 32754, 32717, 32658, 32577, 32473, 32348, 32200, 32029, 31837, 31624, 31388, 31131, 30853, 30553, 30232, 29891, 29530, 29148, 28746, 28324, 27883, 27423, 26944, 26447, 25931, 25398, 24847, 24279, 23695, 23095, 22478, 21846, 21199, 20538, 19863, 19174, 18472, 17757, 17030, 16291, 15541, 14781, 14010, 13230, 12441, 11643, 10837, 10024, 9204, 8377, 7545, 6708, 5866, 5020, 4171, 3319, 2464, 1608, 751, -107, -965, -1822, -2678, -3532, -4383, -5232, -6077, -6918, -7754, -8585, -9409, -10228, -11039, -11843, -12639, -13426, -14204, -14972, -15730, -16477, -17213, -17937, -18648, -19347, -20033, -20705, -21363, -22006, -22634, -23246, -23843, -24423, -24986, -25533, -26062, -26573, -27066, -27540, -27995, -28431, -28848, -29245, -29622, -29979, -30315, -30630, -30924, -31197, -31449, -31679, -31887, -32074, -32239, -32381, -32501, -32600, -32675, -32729, -32759 }; internal static readonly int[] intensity_thresholds = new int[21] { 1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 36, 44, 50, 56, 62, 67, 72, 79, 88, 106, 134 }; internal static readonly int[] intensity_histeresis = new int[21] { 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 5, 6, 8, 8 }; } internal static class VQ { private static int[] SPREAD_FACTOR = new int[3] { 15, 10, 5 }; internal static void exp_rotation1(Span X, int X_ptr, int len, int stride, int c, int s) { int num = X_ptr; int a = Inlines.NEG16(s); for (int i = 0; i < len - stride; i++) { int b = X[num]; int b2 = X[num + stride]; X[num + stride] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MAC16_16(Inlines.MULT16_16(c, b2), s, b), 15)); X[num] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MAC16_16(Inlines.MULT16_16(c, b), a, b2), 15)); num++; } num = X_ptr + (len - 2 * stride - 1); for (int i = len - 2 * stride - 1; i >= 0; i--) { int b3 = X[num]; int b4 = X[num + stride]; X[num + stride] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MAC16_16(Inlines.MULT16_16(c, b4), s, b3), 15)); X[num] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MAC16_16(Inlines.MULT16_16(c, b3), a, b4), 15)); num--; } } internal static void exp_rotation(Span X, int X_ptr, int len, int dir, int stride, int K, int spread) { int i = 0; if (2 * K >= len || spread == 0) { return; } int num = SPREAD_FACTOR[spread - 1]; int num2 = Inlines.celt_div(Inlines.MULT16_16(32767, len), len + num * K); int num3 = Inlines.HALF16(Inlines.MULT16_16_Q15(num2, num2)); int num4 = Inlines.celt_cos_norm(Inlines.EXTEND32(num3)); int num5 = Inlines.celt_cos_norm(Inlines.EXTEND32(Inlines.SUB16(32767, num3))); if (len >= 8 * stride) { for (i = 1; (i * i + i) * stride + (stride >> 2) < len; i++) { } } len = Inlines.celt_udiv(len, stride); for (int j = 0; j < stride; j++) { if (dir < 0) { if (i != 0) { exp_rotation1(X, X_ptr + j * len, len, i, num5, num4); } exp_rotation1(X, X_ptr + j * len, len, 1, num4, num5); } else { exp_rotation1(X, X_ptr + j * len, len, 1, num4, (short)(-num5)); if (i != 0) { exp_rotation1(X, X_ptr + j * len, len, i, num5, (short)(-num4)); } } } } internal static void normalise_residual(int[] iy, Span X, int X_ptr, int N, int Ryy, int gain) { int num = Inlines.celt_ilog2(Ryy) >> 1; int a = Inlines.MULT16_16_P15(Inlines.celt_rsqrt_norm(Inlines.VSHR32(Ryy, 2 * (num - 7))), gain); int num2 = 0; do { X[X_ptr + num2] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MULT16_16(a, iy[num2]), num + 1)); } while (++num2 < N); } internal static uint extract_collapse_mask(int[] iy, int N, int B) { if (B <= 1) { return 1u; } int num = Inlines.celt_udiv(N, B); uint num2 = 0u; int num3 = 0; do { uint num4 = 0u; int num5 = 0; do { num4 |= (uint)iy[num3 * num + num5]; } while (++num5 < num); num2 |= ((num4 != 0) ? 1u : 0u) << num3; } while (++num3 < B); return num2; } internal static uint alg_quant(Span X, int X_ptr, int N, int K, int spread, int B, EntropyCoder enc, Span encodedData) { int[] array = new int[N]; int[] array2 = new int[N]; int[] array3 = new int[N]; exp_rotation(X, X_ptr, N, 1, B, K, spread); int num = 0; int num2 = 0; do { int index = X_ptr + num2; array3[num2] = ((X[index] > 0) ? 1 : (-1)); X[index] = Inlines.ABS16(X[index]); array2[num2] = 0; array[num2] = 0; } while (++num2 < N); int num3; int num4 = (num3 = 0); int num5 = K; if (K > N >> 1) { num2 = 0; do { num += X[X_ptr + num2]; } while (++num2 < N); if (num <= K) { X[X_ptr] = 16384; num2 = X_ptr + 1; do { X[num2] = 0; } while (++num2 < N + X_ptr); num = 16384; } int b = Inlines.EXTRACT16(Inlines.MULT16_32_Q16(K - 1, Inlines.celt_rcp(num))); num2 = 0; do { array2[num2] = Inlines.MULT16_16_Q15(X[X_ptr + num2], b); array[num2] = array2[num2]; num3 = Inlines.MAC16_16(num3, array[num2], array[num2]); num4 = Inlines.MAC16_16(num4, X[X_ptr + num2], array[num2]); array[num2] *= 2; num5 -= array2[num2]; } while (++num2 < N); } if (num5 > N + 3) { int num6 = num5; num3 = Inlines.MAC16_16(num3, num6, num6); num3 = Inlines.MAC16_16(num3, num6, array[0]); array2[0] += num5; num5 = 0; } int num7 = 1; for (int i = 0; i < num5; i++) { int b2 = -32767; int a = 0; int shift = 1 + Inlines.celt_ilog2(K - num5 + i + 1); int num8 = 0; num3 = Inlines.ADD16(num3, 1); num2 = 0; do { int num9 = Inlines.EXTRACT16(Inlines.SHR32(Inlines.ADD32(num4, Inlines.EXTEND32(X[X_ptr + num2])), shift)); int num10 = Inlines.ADD16(num3, array[num2]); num9 = Inlines.MULT16_16_Q15(num9, num9); if (Inlines.MULT16_16(a, num9) > Inlines.MULT16_16(num10, b2)) { a = num10; b2 = num9; num8 = num2; } } while (++num2 < N); num4 = Inlines.ADD32(num4, Inlines.EXTEND32(X[X_ptr + num8])); num3 = Inlines.ADD16(num3, array[num8]); array[num8] += 2 * num7; array2[num8]++; } num2 = 0; do { X[X_ptr + num2] = Inlines.MULT16_16(array3[num2], X[X_ptr + num2]); array2[num2] = ((array3[num2] < 0) ? (-array2[num2]) : array2[num2]); } while (++num2 < N); CWRS.encode_pulses(array2, N, K, enc, encodedData); return extract_collapse_mask(array2, N, B); } internal static uint alg_unquant(Span X, int X_ptr, int N, int K, int spread, int B, EntropyCoder dec, ReadOnlySpan encodedData, int gain) { int[] array = new int[N]; int ryy = CWRS.decode_pulses(array, N, K, dec, encodedData); normalise_residual(array, X, X_ptr, N, ryy, gain); exp_rotation(X, X_ptr, N, -1, B, K, spread); return extract_collapse_mask(array, N, B); } internal static void renormalise_vector(Span X, int N, int gain) { int num = 1 + Kernels.celt_inner_prod(X, X, N); int num2 = Inlines.celt_ilog2(num) >> 1; int a = Inlines.MULT16_16_P15(Inlines.celt_rsqrt_norm(Inlines.VSHR32(num, 2 * (num2 - 7))), gain); int num3 = 0; for (int i = 0; i < N; i++) { X[num3] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MULT16_16(a, X[num3]), num2 + 1)); num3++; } } internal static int stereo_itheta(Span X, Span Y, int stereo, int N) { int num; int num2 = (num = 1); if (stereo != 0) { for (int i = 0; i < N; i++) { int num3 = Inlines.ADD16(Inlines.SHR16(X[i], 1), Inlines.SHR16(Y[i], 1)); int num4 = Inlines.SUB16(Inlines.SHR16(X[i], 1), Inlines.SHR16(Y[i], 1)); num2 = Inlines.MAC16_16(num2, num3, num3); num = Inlines.MAC16_16(num, num4, num4); } } else { num2 += Kernels.celt_inner_prod(X, X, N); num += Kernels.celt_inner_prod(Y, Y, N); } int x = Inlines.celt_sqrt(num2); int y = Inlines.celt_sqrt(num); return Inlines.MULT16_16_Q15(20861, Inlines.celt_atan2p(y, x)); } } } namespace Concentus.Celt.Structs { internal class AnalysisInfo { internal int valid; internal float tonality; internal float tonality_slope; internal float noisiness; internal float activity; internal float music_prob; internal int bandwidth; internal AnalysisInfo() { } internal void Assign(AnalysisInfo other) { valid = other.valid; tonality = other.tonality; tonality_slope = other.tonality_slope; noisiness = other.noisiness; activity = other.activity; music_prob = other.music_prob; bandwidth = other.bandwidth; } internal void Reset() { valid = 0; tonality = 0f; tonality_slope = 0f; noisiness = 0f; activity = 0f; music_prob = 0f; bandwidth = 0; } } internal class CeltDecoder { internal CeltMode mode; internal int overlap; internal int channels; internal int stream_channels; internal int downsample; internal int start; internal int end; internal int signalling; internal uint rng; internal int error; internal int last_pitch_index; internal int loss_count; internal int postfilter_period; internal int postfilter_period_old; internal int postfilter_gain; internal int postfilter_gain_old; internal int postfilter_tapset; internal int postfilter_tapset_old; internal readonly int[] preemph_memD = new int[2]; internal int[][] decode_mem; internal int[][] lpc; internal int[] oldEBands; internal int[] oldLogE; internal int[] oldLogE2; internal int[] backgroundLogE; private void Reset() { mode = null; overlap = 0; channels = 0; stream_channels = 0; downsample = 0; start = 0; end = 0; signalling = 0; PartialReset(); } private void PartialReset() { rng = 0u; error = 0; last_pitch_index = 0; loss_count = 0; postfilter_period = 0; postfilter_period_old = 0; postfilter_gain = 0; postfilter_gain_old = 0; postfilter_tapset = 0; postfilter_tapset_old = 0; Arrays.MemSetInt(preemph_memD, 0, 2); decode_mem = null; lpc = null; oldEBands = null; oldLogE = null; oldLogE2 = null; backgroundLogE = null; } internal void ResetState() { PartialReset(); decode_mem = new int[channels][]; lpc = new int[channels][]; for (int i = 0; i < channels; i++) { decode_mem[i] = new int[2048 + mode.overlap]; lpc[i] = new int[24]; } oldEBands = new int[2 * mode.nbEBands]; oldLogE = new int[2 * mode.nbEBands]; oldLogE2 = new int[2 * mode.nbEBands]; backgroundLogE = new int[2 * mode.nbEBands]; for (int j = 0; j < 2 * mode.nbEBands; j++) { oldLogE[j] = (oldLogE2[j] = -28672); } } internal int celt_decoder_init(int sampling_rate, int channels) { int num = opus_custom_decoder_init(CeltMode.mode48000_960_120, channels); if (num != 0) { return num; } downsample = CeltCommon.resampling_factor(sampling_rate); if (downsample == 0) { return -1; } return 0; } private int opus_custom_decoder_init(CeltMode mode, int channels) { if (channels < 0 || channels > 2) { return -1; } if (this == null) { return -7; } Reset(); this.mode = mode; overlap = mode.overlap; stream_channels = (this.channels = channels); downsample = 1; start = 0; end = this.mode.effEBands; signalling = 1; loss_count = 0; ResetState(); return 0; } internal void celt_decode_lost(int N, int LM) { int num = channels; int[][] array = new int[2][]; int[] array2 = new int[2]; CeltMode celtMode = mode; int nbEBands = celtMode.nbEBands; int num2 = celtMode.overlap; short[] eBands = celtMode.eBands; int num3 = 0; do { array[num3] = decode_mem[num3]; array2[num3] = 2048 - N; } while (++num3 < num); if ((loss_count >= 5 || start != 0) ? true : false) { int num4 = end; int num5 = Inlines.IMAX(start, Inlines.IMIN(num4, celtMode.effEBands)); int[][] array3 = Arrays.InitTwoDimensionalArray(num, N); int num6 = ((loss_count == 0) ? 1536 : 512); num3 = 0; do { for (int i = start; i < num4; i++) { oldEBands[num3 * nbEBands + i] = Inlines.MAX16(backgroundLogE[num3 * nbEBands + i], oldEBands[num3 * nbEBands + i] - num6); } } while (++num3 < num); uint num7 = rng; for (num3 = 0; num3 < num; num3++) { for (int i = start; i < num5; i++) { int num8 = eBands[i] << LM; int num9 = eBands[i + 1] - eBands[i] << LM; for (int j = 0; j < num9; j++) { num7 = Bands.celt_lcg_rand(num7); array3[num3][num8 + j] = (int)num7 >> 20; } VQ.renormalise_vector(array3[num3].AsSpan(), num9, 32767); } } rng = num7; num3 = 0; do { Arrays.MemMoveInt(decode_mem[num3], N, 0, 2048 - N + (num2 >> 1)); } while (++num3 < num); CeltCommon.celt_synthesis(celtMode, array3, array, array2, oldEBands, start, num5, num, num, 0, LM, downsample, 0); } else { int a = 32767; int num10; if (loss_count == 0) { num10 = (last_pitch_index = CeltCommon.celt_plc_pitch_search(decode_mem, num)); } else { num10 = last_pitch_index; a = 26214; } int[] array4 = new int[num2]; int[] array5 = new int[1024]; Span mem = stackalloc int[24]; int[] window = celtMode.window; num3 = 0; do { int num11 = 0; int[] array6 = decode_mem[num3]; int i; for (i = 0; i < 1024; i++) { array5[i] = Inlines.ROUND16(array6[1024 + i], 12); } if (loss_count == 0) { int[] array7 = new int[25]; Autocorrelation._celt_autocorr(array5, array7, window, num2, 24, 1024); array7[0] += Inlines.SHR32(array7[0], 13); for (i = 1; i <= 24; i++) { array7[i] -= Inlines.MULT16_32_Q15(2 * i * i, array7[i]); } CeltLPC.celt_lpc(lpc[num3], array7, 24); } int num12 = Inlines.IMIN(2 * num10, 1024); for (i = 0; i < 24; i++) { mem[i] = Inlines.ROUND16(array6[2048 - num12 - 1 - i], 12); } Span span = array5.AsSpan(); Span x = span.Slice(1024 - num12); Span num13 = lpc[num3].AsSpan(); span = array5.AsSpan(); Kernels.celt_fir(x, num13, span.Slice(1024 - num12), num12, 24, mem); int num14 = 1; int num15 = 1; int shift = Inlines.IMAX(0, 2 * Inlines.celt_zlog2(Inlines.celt_maxabs16(array5, 1024 - num12, num12)) - 20); int num16 = num12 >> 1; for (i = 0; i < num16; i++) { int num17 = array5[1024 - num16 + i]; num14 += Inlines.SHR32(Inlines.MULT16_16(num17, num17), shift); num17 = array5[1024 - 2 * num16 + i]; num15 += Inlines.SHR32(Inlines.MULT16_16(num17, num17), shift); } num14 = Inlines.MIN32(num14, num15); int b = Inlines.celt_sqrt(Inlines.frac_div32(Inlines.SHR32(num14, 1), num15)); Arrays.MemMoveInt(array6, N, 0, 2048 - N); int num18 = 1024 - num10; int num19 = N + num2; int a2 = Inlines.MULT16_16_Q15(a, b); int num20; i = (num20 = 0); while (i < num19) { if (num20 >= num10) { num20 -= num10; a2 = Inlines.MULT16_16_Q15(a2, b); } array6[2048 - N + i] = Inlines.SHL32(Inlines.MULT16_16_Q15(a2, array5[num18 + num20]), 12); int num21 = Inlines.ROUND16(array6[1024 - N + num18 + num20], 12); num11 += Inlines.SHR32(Inlines.MULT16_16(num21, num21), 8); i++; num20++; } for (i = 0; i < 24; i++) { mem[i] = Inlines.ROUND16(array6[2048 - N - 1 - i], 12); } span = array6.AsSpan(); Span x2 = span.Slice(2048 - N); int[] den = lpc[num3]; span = array6.AsSpan(); CeltLPC.celt_iir(x2, den, span.Slice(2048 - N), num19, 24, mem); int num22 = 0; for (i = 0; i < num19; i++) { int num23 = Inlines.ROUND16(array6[2048 - N + i], 12); num22 += Inlines.SHR32(Inlines.MULT16_16(num23, num23), 8); } if (num11 <= Inlines.SHR32(num22, 2)) { for (i = 0; i < num19; i++) { array6[2048 - N + i] = 0; } } else if (num11 < num22) { int num24 = Inlines.celt_sqrt(Inlines.frac_div32(Inlines.SHR32(num11, 1) + 1, num22 + 1)); for (i = 0; i < num2; i++) { int a3 = 32767 - Inlines.MULT16_16_Q15(window[i], 32767 - num24); array6[2048 - N + i] = Inlines.MULT16_32_Q15(a3, array6[2048 - N + i]); } for (i = num2; i < num19; i++) { array6[2048 - N + i] = Inlines.MULT16_32_Q15(num24, array6[2048 - N + i]); } } CeltCommon.comb_filter(array4, 0, array6, 2048, postfilter_period, postfilter_period, num2, -postfilter_gain, -postfilter_gain, postfilter_tapset, postfilter_tapset, null, 0); for (i = 0; i < num2 / 2; i++) { array6[2048 + i] = Inlines.MULT16_32_Q15(window[i], array4[num2 - 1 - i]) + Inlines.MULT16_32_Q15(window[num2 - i - 1], array4[i]); } } while (++num3 < num); } loss_count++; } internal int celt_decode_with_ec(ReadOnlySpan data, int data_ptr, int len, Span pcm, int pcm_ptr, int frame_size, EntropyCoder dec, int accum) { int[][] array = new int[2][]; int[] array2 = new int[2]; int num = channels; int intensity = 0; int dual_stereo = 0; int num2 = 0; int num3 = stream_channels; CeltMode celtMode = mode; int nbEBands = celtMode.nbEBands; int num4 = celtMode.overlap; short[] eBands = celtMode.eBands; int num5 = start; int num6 = end; frame_size *= downsample; int[] array3 = oldEBands; int[] array4 = oldLogE; int[] array5 = oldLogE2; int[] array6 = backgroundLogE; int i; for (i = 0; i <= celtMode.maxLM && celtMode.shortMdctSize << i != frame_size; i++) { } if (i > celtMode.maxLM) { return -1; } int num7 = 1 << i; if (len < 0 || len > 1275 || pcm.IsEmpty) { return -1; } int num8 = num7 * celtMode.shortMdctSize; int num9 = 0; do { array[num9] = decode_mem[num9]; array2[num9] = 2048 - num8; } while (++num9 < num); int num10 = num6; if (num10 > celtMode.effEBands) { num10 = celtMode.effEBands; } if (data.IsEmpty || len <= 1) { celt_decode_lost(num8, i); CeltCommon.deemphasis(array, array2, pcm, pcm_ptr, num8, num, downsample, celtMode.preemph, preemph_memD, accum); return frame_size / downsample; } if (dec == null) { dec = new EntropyCoder(); dec.dec_init(data.Slice(data_ptr), (uint)len); } if (num3 == 1) { for (int j = 0; j < nbEBands; j++) { array3[j] = Inlines.MAX16(array3[j], array3[nbEBands + j]); } } int num11 = len * 8; int num12 = dec.tell(); int num13 = ((num12 >= num11) ? 1 : ((num12 == 1) ? dec.dec_bit_logp(data.Slice(data_ptr), 15u) : 0)); if (num13 != 0) { num12 = len * 8; dec.nbits_total += num12 - dec.tell(); } int g = 0; int t = 0; int tapset = 0; if (num5 == 0 && num12 + 16 <= num11) { if (dec.dec_bit_logp(data.Slice(data_ptr), 1u) != 0) { int num14 = (int)dec.dec_uint(data.Slice(data_ptr), 6u); t = (16 << num14) + (int)dec.dec_bits(data.Slice(data_ptr), (uint)(4 + num14)) - 1; int num15 = (int)dec.dec_bits(data.Slice(data_ptr), 3u); if (dec.tell() + 2 <= num11) { tapset = dec.dec_icdf(data.Slice(data_ptr), Tables.tapset_icdf, 2u); } g = 3072 * (num15 + 1); } num12 = dec.tell(); } int num16; if (i > 0 && num12 + 3 <= num11) { num16 = dec.dec_bit_logp(data.Slice(data_ptr), 3u); num12 = dec.tell(); } else { num16 = 0; } int shortBlocks = ((num16 != 0) ? num7 : 0); int intra = ((num12 + 3 <= num11) ? dec.dec_bit_logp(data.Slice(data_ptr), 3u) : 0); QuantizeBands.unquant_coarse_energy(celtMode, num5, num6, array3, intra, dec, data.Slice(data_ptr), num3, i); int[] tf_res = new int[nbEBands]; CeltCommon.tf_decode(num5, num6, num16, tf_res, i, dec, data.Slice(data_ptr)); num12 = dec.tell(); int spread = 2; if (num12 + 4 <= num11) { spread = dec.dec_icdf(data.Slice(data_ptr), Tables.spread_icdf, 5u); } int[] array7 = new int[nbEBands]; CeltCommon.init_caps(celtMode, array7, i, num3); int[] array8 = new int[nbEBands]; int num17 = 6; num11 <<= 3; num12 = (int)dec.tell_frac(); for (int j = num5; j < num6; j++) { int num18 = num3 * (eBands[j + 1] - eBands[j]) << i; int num19 = Inlines.IMIN(num18 << 3, Inlines.IMAX(48, num18)); int num20 = num17; int num21 = 0; while (num12 + (num20 << 3) < num11 && num21 < array7[j]) { int num22 = dec.dec_bit_logp(data.Slice(data_ptr), (uint)num20); num12 = (int)dec.tell_frac(); if (num22 == 0) { break; } num21 += num19; num11 -= num19; num20 = 1; } array8[j] = num21; if (num21 > 0) { num17 = Inlines.IMAX(2, num17 - 1); } } int[] array9 = new int[nbEBands]; int alloc_trim = ((num12 + 48 <= num11) ? dec.dec_icdf(data.Slice(data_ptr), Tables.trim_icdf, 7u) : 5); int num23 = (len * 8 << 3) - (int)dec.tell_frac() - 1; int num24 = ((num16 != 0 && i >= 2 && num23 >= i + 2 << 3) ? 8 : 0); num23 -= num24; int[] pulses = new int[nbEBands]; int[] fine_priority = new int[nbEBands]; int balance; int codedBands = Rate.compute_allocation_decode(celtMode, num5, num6, array8, array7, alloc_trim, ref intensity, ref dual_stereo, num23, out balance, pulses, array9, fine_priority, num3, i, dec, data.Slice(data_ptr), 0, 0); QuantizeBands.unquant_fine_energy(celtMode, num5, num6, array3, array9, dec, data.Slice(data_ptr), num3); num9 = 0; do { Arrays.MemMoveInt(decode_mem[num9], num8, 0, 2048 - num8 + num4 / 2); } while (++num9 < num); byte[] collapse_masks = new byte[num3 * nbEBands]; int[][] array10 = Arrays.InitTwoDimensionalArray(num3, num8); Bands.quant_all_bands_decode(0, celtMode, num5, num6, array10[0], (num3 == 2) ? array10[1] : null, collapse_masks, null, pulses, shortBlocks, spread, dual_stereo, intensity, tf_res, len * 64 - num24, balance, dec, data.Slice(data_ptr), i, codedBands, ref rng); if (num24 > 0) { num2 = (int)dec.dec_bits(data.Slice(data_ptr), 1u); } QuantizeBands.unquant_energy_finalise(celtMode, num5, num6, array3, array9, fine_priority, len * 8 - dec.tell(), dec, data.Slice(data_ptr), num3); if (num2 != 0) { Bands.anti_collapse(celtMode, array10, collapse_masks, i, num3, num8, num5, num6, array3, array4, array5, pulses, rng); } if (num13 != 0) { for (int j = 0; j < num3 * nbEBands; j++) { array3[j] = -28672; } } CeltCommon.celt_synthesis(celtMode, array10, array, array2, array3, num5, num10, num3, num, num16, i, downsample, num13); num9 = 0; do { postfilter_period = Inlines.IMAX(postfilter_period, 15); postfilter_period_old = Inlines.IMAX(postfilter_period_old, 15); CeltCommon.comb_filter(array[num9], array2[num9], array[num9], array2[num9], postfilter_period_old, postfilter_period, celtMode.shortMdctSize, postfilter_gain_old, postfilter_gain, postfilter_tapset_old, postfilter_tapset, celtMode.window, num4); if (i != 0) { CeltCommon.comb_filter(array[num9], array2[num9] + celtMode.shortMdctSize, array[num9], array2[num9] + celtMode.shortMdctSize, postfilter_period, t, num8 - celtMode.shortMdctSize, postfilter_gain, g, postfilter_tapset, tapset, celtMode.window, num4); } } while (++num9 < num); postfilter_period_old = postfilter_period; postfilter_gain_old = postfilter_gain; postfilter_tapset_old = postfilter_tapset; postfilter_period = t; postfilter_gain = g; postfilter_tapset = tapset; if (i != 0) { postfilter_period_old = postfilter_period; postfilter_gain_old = postfilter_gain; postfilter_tapset_old = postfilter_tapset; } if (num3 == 1) { Arrays.MemCopy(array3, 0, array3, nbEBands, nbEBands); } if (num16 == 0) { Arrays.MemCopy(array4, 0, array5, 0, 2 * nbEBands); Arrays.MemCopy(array3, 0, array4, 0, 2 * nbEBands); int num25 = ((loss_count >= 10) ? 1024 : num7); for (int j = 0; j < 2 * nbEBands; j++) { array6[j] = Inlines.MIN16(array6[j] + num25, array3[j]); } } else { for (int j = 0; j < 2 * nbEBands; j++) { array4[j] = Inlines.MIN16(array4[j], array3[j]); } } num9 = 0; do { for (int j = 0; j < num5; j++) { array3[num9 * nbEBands + j] = 0; array4[num9 * nbEBands + j] = (array5[num9 * nbEBands + j] = -28672); } for (int j = num6; j < nbEBands; j++) { array3[num9 * nbEBands + j] = 0; array4[num9 * nbEBands + j] = (array5[num9 * nbEBands + j] = -28672); } } while (++num9 < 2); rng = dec.rng; CeltCommon.deemphasis(array, array2, pcm, pcm_ptr, num8, num, downsample, celtMode.preemph, preemph_memD, accum); loss_count = 0; if (dec.tell() > 8 * len) { return -3; } if (dec.get_error() != 0) { error = 1; } return frame_size / downsample; } internal void SetStartBand(int value) { if (value < 0 || value >= mode.nbEBands) { throw new ArgumentException("Start band above max number of ebands (or negative)"); } start = value; } internal void SetEndBand(int value) { if (value < 1 || value > mode.nbEBands) { throw new ArgumentException("End band above max number of ebands (or less than 1)"); } end = value; } internal void SetChannels(int value) { if (value < 1 || value > 2) { throw new ArgumentException("Channel count must be 1 or 2"); } stream_channels = value; } internal int GetAndClearError() { int result = error; error = 0; return result; } internal int GetLookahead() { return overlap / downsample; } internal int GetPitch() { return postfilter_period; } internal CeltMode GetMode() { return mode; } internal void SetSignalling(int value) { signalling = value; } internal uint GetFinalRange() { return rng; } } internal class CeltEncoder { internal CeltMode mode; internal int channels; internal int stream_channels; internal int force_intra; internal int clip; internal int disable_pf; internal int complexity; internal int upsample; internal int start; internal int end; internal int bitrate; internal int vbr; internal int signalling; internal int constrained_vbr; internal int loss_rate; internal int lsb_depth; internal OpusFramesize variable_duration; internal int lfe; internal uint rng; internal int spread_decision; internal int delayedIntra; internal int tonal_average; internal int lastCodedBands; internal int hf_average; internal int tapset_decision; internal int prefilter_period; internal int prefilter_gain; internal int prefilter_tapset; internal int consec_transient; internal AnalysisInfo analysis = new AnalysisInfo(); internal readonly int[] preemph_memE = new int[2]; internal readonly int[] preemph_memD = new int[2]; internal int vbr_reservoir; internal int vbr_drift; internal int vbr_offset; internal int vbr_count; internal int overlap_max; internal int stereo_saving; internal int intensity; internal int[] energy_mask; internal int spec_avg; internal int[][] in_mem; internal int[][] prefilter_mem; internal int[][] oldBandE; internal int[][] oldLogE; internal int[][] oldLogE2; private void Reset() { mode = null; channels = 0; stream_channels = 0; force_intra = 0; clip = 0; disable_pf = 0; complexity = 0; upsample = 0; start = 0; end = 0; bitrate = 0; vbr = 0; signalling = 0; constrained_vbr = 0; loss_rate = 0; lsb_depth = 0; variable_duration = (OpusFramesize)0; lfe = 0; PartialReset(); } private void PartialReset() { rng = 0u; spread_decision = 0; delayedIntra = 0; tonal_average = 0; lastCodedBands = 0; hf_average = 0; tapset_decision = 0; prefilter_period = 0; prefilter_gain = 0; prefilter_tapset = 0; consec_transient = 0; analysis.Reset(); preemph_memE[0] = 0; preemph_memE[1] = 0; preemph_memD[0] = 0; preemph_memD[1] = 0; vbr_reservoir = 0; vbr_drift = 0; vbr_offset = 0; vbr_count = 0; overlap_max = 0; stereo_saving = 0; intensity = 0; energy_mask = null; spec_avg = 0; in_mem = null; prefilter_mem = null; oldBandE = null; oldLogE = null; oldLogE2 = null; } internal void ResetState() { PartialReset(); in_mem = Arrays.InitTwoDimensionalArray(channels, mode.overlap); prefilter_mem = Arrays.InitTwoDimensionalArray(channels, 1024); oldBandE = Arrays.InitTwoDimensionalArray(channels, mode.nbEBands); oldLogE = Arrays.InitTwoDimensionalArray(channels, mode.nbEBands); oldLogE2 = Arrays.InitTwoDimensionalArray(channels, mode.nbEBands); for (int i = 0; i < mode.nbEBands; i++) { oldLogE[0][i] = (oldLogE2[0][i] = -28672); } if (channels == 2) { for (int i = 0; i < mode.nbEBands; i++) { oldLogE[1][i] = (oldLogE2[1][i] = -28672); } } vbr_offset = 0; delayedIntra = 1; spread_decision = 2; tonal_average = 256; hf_average = 0; tapset_decision = 0; } internal int opus_custom_encoder_init_arch(CeltMode mode, int channels) { if (channels < 0 || channels > 2) { return -1; } if (this == null || mode == null) { return -7; } Reset(); this.mode = mode; stream_channels = (this.channels = channels); upsample = 1; start = 0; end = this.mode.effEBands; signalling = 1; constrained_vbr = 1; clip = 1; bitrate = -1; vbr = 0; force_intra = 0; complexity = 5; lsb_depth = 24; ResetState(); return 0; } internal int celt_encoder_init(int sampling_rate, int channels) { int num = opus_custom_encoder_init_arch(CeltMode.mode48000_960_120, channels); if (num != 0) { return num; } upsample = CeltCommon.resampling_factor(sampling_rate); return 0; } internal int run_prefilter(int[][] input, int[][] prefilter_mem, int CC, int N, int prefilter_tapset, out int pitch, out int gain, out int qgain, int enabled, int nbAvailableBytes) { int[][] array = new int[CC][]; CeltMode celtMode = mode; int overlap = celtMode.overlap; for (int i = 0; i < CC; i++) { array[i] = new int[N + 1024]; } int num = 0; do { Arrays.MemCopy(prefilter_mem[num], 0, array[num], 0, 1024); Arrays.MemCopy(input[num], overlap, array[num], 1024, N); } while (++num < CC); int pitch2; int b; if (enabled != 0) { int[] array2 = new int[1024 + N >> 1]; Pitch.pitch_downsample(array, array2, 1024 + N, CC); Pitch.pitch_search(array2, 512, array2, N, 979, out pitch2); pitch2 = 1024 - pitch2; b = Pitch.remove_doubling(array2, 1024, 15, N, ref pitch2, prefilter_period, prefilter_gain); if (pitch2 > 1022) { pitch2 = 1022; } b = Inlines.MULT16_16_Q15(22938, b); if (loss_rate > 2) { b = Inlines.HALF32(b); } if (loss_rate > 4) { b = Inlines.HALF32(b); } if (loss_rate > 8) { b = 0; } } else { b = 0; pitch2 = 15; } int num2 = 6554; if (Inlines.abs(pitch2 - prefilter_period) * 10 > pitch2) { num2 += 6554; } if (nbAvailableBytes < 25) { num2 += 3277; } if (nbAvailableBytes < 35) { num2 += 3277; } if (prefilter_gain > 13107) { num2 -= 3277; } if (prefilter_gain > 18022) { num2 -= 3277; } num2 = Inlines.MAX16(num2, 6554); int result; int num3; if (b < num2) { b = 0; result = 0; num3 = 0; } else { if (Inlines.ABS32(b - prefilter_gain) < 3277) { b = prefilter_gain; } num3 = (b + 1536 >> 10) / 3 - 1; num3 = Inlines.IMAX(0, Inlines.IMIN(7, num3)); b = 3072 * (num3 + 1); result = 1; } num = 0; do { int num4 = celtMode.shortMdctSize - overlap; prefilter_period = Inlines.IMAX(prefilter_period, 15); Arrays.MemCopy(in_mem[num], 0, input[num], 0, overlap); if (num4 != 0) { CeltCommon.comb_filter(input[num], overlap, array[num], 1024, prefilter_period, prefilter_period, num4, -prefilter_gain, -prefilter_gain, this.prefilter_tapset, this.prefilter_tapset, null, 0); } CeltCommon.comb_filter(input[num], overlap + num4, array[num], 1024 + num4, prefilter_period, pitch2, N - num4, -prefilter_gain, -b, this.prefilter_tapset, prefilter_tapset, celtMode.window, overlap); Arrays.MemCopy(input[num], N, in_mem[num], 0, overlap); if (N > 1024) { Arrays.MemCopy(array[num], N, prefilter_mem[num], 0, 1024); continue; } Arrays.MemMoveInt(prefilter_mem[num], N, 0, 1024 - N); Arrays.MemCopy(array[num], 1024, prefilter_mem[num], 1024 - N, N); } while (++num < CC); gain = b; pitch = pitch2; qgain = num3; return result; } internal int celt_encode_with_ec(Span pcm, int pcm_ptr, int frame_size, Span compressed, int compressed_ptr, int nbCompressedBytes, EntropyCoder enc) { int num = 0; int num2 = 0; int num3 = channels; int num4 = stream_channels; int pitch = 15; int gain = 0; int dual_stereo = 0; int num5 = 0; int num6 = 0; int num7 = 0; int tf_chan = 0; int pitch_change = 0; int num8 = 0; int surround_masking = 0; int num9 = 0; int surround_trim = 0; int num10 = 510000; CeltMode celtMode = mode; int nbEBands = celtMode.nbEBands; int overlap = celtMode.overlap; short[] eBands = celtMode.eBands; int num11 = start; int num12 = end; int tf_estimate = 0; if (nbCompressedBytes < 2 || pcm.IsEmpty) { return -1; } frame_size *= upsample; int i; for (i = 0; i <= celtMode.maxLM && celtMode.shortMdctSize << i != frame_size; i++) { } if (i > celtMode.maxLM) { return -1; } int num13 = 1 << i; int num14 = num13 * celtMode.shortMdctSize; int num16; int num15; if (enc == null) { num15 = 1; num16 = 0; } else { num15 = enc.tell(); num16 = num15 + 4 >> 3; } nbCompressedBytes = Inlines.IMIN(nbCompressedBytes, 1275); int num17 = nbCompressedBytes - num16; int num19; int num20; if (vbr != 0 && bitrate != -1) { int num18 = celtMode.Fs >> 3; num19 = (bitrate * frame_size + (num18 >> 1)) / num18; num20 = num19 >> 6; } else { num19 = 0; int num21 = bitrate * frame_size; if (num15 > 1) { num21 += num15; } if (bitrate != -1) { nbCompressedBytes = Inlines.IMAX(2, Inlines.IMIN(nbCompressedBytes, (num21 + 4 * celtMode.Fs) / (8 * celtMode.Fs) - ((signalling != 0) ? 1 : 0))); } num20 = nbCompressedBytes; } if (bitrate != -1) { num10 = bitrate - (40 * num4 + 20) * ((400 >> i) - 50); } if (enc == null) { enc = new EntropyCoder(); enc.enc_init((uint)nbCompressedBytes); } if (num19 > 0 && constrained_vbr != 0) { int num22 = num19; int num23 = Inlines.IMIN(Inlines.IMAX((num15 == 1) ? 2 : 0, num19 + num22 - vbr_reservoir >> 6), num17); if (num23 < num17) { nbCompressedBytes = num16 + num23; num17 = num23; enc.enc_shrink(compressed.Slice(compressed_ptr), (uint)nbCompressedBytes); } } int num24 = nbCompressedBytes * 8; int num25 = num12; if (num25 > celtMode.effEBands) { num25 = celtMode.effEBands; } int[][] array = Arrays.InitTwoDimensionalArray(num3, num14 + overlap); int a = Inlines.MAX32(overlap_max, Inlines.celt_maxabs32(pcm, pcm_ptr, num4 * (num14 - overlap) / upsample)); overlap_max = Inlines.celt_maxabs32(pcm, pcm_ptr + num4 * (num14 - overlap) / upsample, num4 * overlap / upsample); num7 = ((Inlines.MAX32(a, overlap_max) == 0) ? 1 : 0); if (num15 == 1) { enc.enc_bit_logp(compressed.Slice(compressed_ptr), num7, 15u); } else { num7 = 0; } if (num7 != 0) { if (num19 > 0) { num20 = (nbCompressedBytes = Inlines.IMIN(nbCompressedBytes, num16 + 2)); num24 = nbCompressedBytes * 8; num17 = 2; enc.enc_shrink(compressed.Slice(compressed_ptr), (uint)nbCompressedBytes); } num15 = nbCompressedBytes * 8; enc.nbits_total += num15 - enc.tell(); } int num26 = 0; do { int num27 = 0; CeltCommon.celt_preemphasis(pcm, pcm_ptr + num26, array[num26], overlap, num14, num3, upsample, celtMode.preemph, ref preemph_memE[num26], num27); } while (++num26 < num3); int enabled = ((((lfe != 0 && num17 > 3) || num17 > 12 * num4) && num11 == 0 && num7 == 0 && disable_pf == 0 && complexity >= 5 && (consec_transient == 0 || i == 3 || variable_duration != OpusFramesize.OPUS_FRAMESIZE_VARIABLE)) ? 1 : 0); num5 = tapset_decision; int qgain; int num28 = run_prefilter(array, prefilter_mem, num3, num14, num5, out pitch, out gain, out qgain, enabled, num17); if ((gain > 13107 || prefilter_gain > 13107) && (analysis.valid == 0 || (double)analysis.tonality > 0.3) && ((double)pitch > 1.26 * (double)prefilter_period || (double)pitch < 0.79 * (double)prefilter_period)) { pitch_change = 1; } if (num28 == 0) { if (num11 == 0 && num15 + 16 <= num24) { enc.enc_bit_logp(compressed.Slice(compressed_ptr), 0, 1u); } } else { enc.enc_bit_logp(compressed.Slice(compressed_ptr), 1, 1u); pitch++; int num29 = Inlines.EC_ILOG((uint)pitch) - 5; enc.enc_uint(compressed.Slice(compressed_ptr), (uint)num29, 6u); enc.enc_bits(compressed.Slice(compressed_ptr), (uint)(pitch - (16 << num29)), (uint)(4 + num29)); pitch--; enc.enc_bits(compressed.Slice(compressed_ptr), (uint)qgain, 3u); enc.enc_icdf(compressed.Slice(compressed_ptr), num5, Tables.tapset_icdf, 2u); } num2 = 0; num = 0; if (complexity >= 1 && lfe == 0) { num2 = CeltCommon.transient_analysis(array, num14 + overlap, num3, out tf_estimate, out tf_chan); } if (i > 0 && enc.tell() + 3 <= num24) { if (num2 != 0) { num = num13; } } else { num2 = 0; num8 = 1; } int[][] array2 = Arrays.InitTwoDimensionalArray(num3, num14); int[][] array3 = Arrays.InitTwoDimensionalArray(num3, nbEBands); int[][] array4 = Arrays.InitTwoDimensionalArray(num3, nbEBands); int num30 = ((num != 0 && complexity >= 8) ? 1 : 0); int[][] array5 = Arrays.InitTwoDimensionalArray(num3, nbEBands); if (num30 != 0) { CeltCommon.compute_mdcts(celtMode, 0, array, array2, num4, num3, i, upsample); Bands.compute_band_energies(celtMode, array2, array3, num25, num4, i); QuantizeBands.amp2Log2(celtMode, num25, num12, array3, array5, num4); for (int j = 0; j < nbEBands; j++) { array5[0][j] += Inlines.HALF16(Inlines.SHL16(i, 10)); } if (num4 == 2) { for (int j = 0; j < nbEBands; j++) { array5[1][j] += Inlines.HALF16(Inlines.SHL16(i, 10)); } } } CeltCommon.compute_mdcts(celtMode, num, array, array2, num4, num3, i, upsample); if (num3 == 2 && num4 == 1) { tf_chan = 0; } Bands.compute_band_energies(celtMode, array2, array3, num25, num4, i); if (lfe != 0) { for (int j = 2; j < num12; j++) { array3[0][j] = Inlines.IMIN(array3[0][j], Inlines.MULT16_32_Q15((short)3, array3[0][0])); array3[0][j] = Inlines.MAX32(array3[0][j], 1); } } QuantizeBands.amp2Log2(celtMode, num25, num12, array3, array4, num4); int[] array6 = new int[num4 * nbEBands]; if (num11 == 0 && energy_mask != null && lfe == 0) { int num31 = 0; int num32 = 0; int num33 = 0; int num34 = Inlines.IMAX(2, lastCodedBands); for (num26 = 0; num26 < num4; num26++) { for (int j = 0; j < num34; j++) { int num35 = Inlines.MAX16(Inlines.MIN16(energy_mask[nbEBands * num26 + j], 256), -2048); if (num35 > 0) { num35 = Inlines.HALF16(num35); } num31 += Inlines.MULT16_16(num35, eBands[j + 1] - eBands[j]); num33 += eBands[j + 1] - eBands[j]; num32 += Inlines.MULT16_16(num35, 1 + 2 * j - num34); } } num31 = Inlines.DIV32_16(num31, num33); num31 += 205; num32 = num32 * 6 / (num4 * (num34 - 1) * (num34 + 1) * num34); num32 = Inlines.HALF32(num32); num32 = Inlines.MAX32(Inlines.MIN32(num32, 32), -32); int k; for (k = 0; eBands[k + 1] < eBands[num34] / 2; k++) { } int num36 = 0; for (int j = 0; j < num34; j++) { int num37 = num31 + num32 * (j - k); int a2 = ((num4 != 2) ? energy_mask[j] : Inlines.MAX16(energy_mask[j], energy_mask[nbEBands + j])); a2 = Inlines.MIN16(a2, 0); a2 -= num37; if (a2 > 256) { array6[j] = a2 - 256; num36++; } } if (num36 >= 3) { num31 += 256; if (num31 > 0) { num31 = 0; num32 = 0; Arrays.MemSetInt(array6, 0, num34); } else { for (int j = 0; j < num34; j++) { array6[j] = Inlines.MAX16(0, array6[j] - 256); } } } num31 += 205; surround_trim = 64 * num32; surround_masking = num31; } if (lfe == 0) { int num38 = -10240; int num39 = 0; int num40 = ((num != 0) ? Inlines.HALF16(Inlines.SHL16(i, 10)) : 0); for (int j = num11; j < num12; j++) { num38 = Inlines.MAX16(num38 - 1024, array4[0][j] - num40); if (num4 == 2) { num38 = Inlines.MAX16(num38, array4[1][j] - num40); } num39 += num38; } num39 /= num12 - num11; num9 = Inlines.SUB16(num39, spec_avg); num9 = Inlines.MIN16(3072, Inlines.MAX16(-1536, num9)); spec_avg += (short)Inlines.MULT16_16_Q15(655, num9); } if (num30 == 0) { Arrays.MemCopy(array4[0], 0, array5[0], 0, nbEBands); if (num4 == 2) { Arrays.MemCopy(array4[1], 0, array5[1], 0, nbEBands); } } if (i > 0 && enc.tell() + 3 <= num24 && num2 == 0 && complexity >= 5 && lfe == 0 && CeltCommon.patch_transient_decision(array4, oldBandE, nbEBands, num11, num12, num4) != 0) { num2 = 1; num = num13; CeltCommon.compute_mdcts(celtMode, num, array, array2, num4, num3, i, upsample); Bands.compute_band_energies(celtMode, array2, array3, num25, num4, i); QuantizeBands.amp2Log2(celtMode, num25, num12, array3, array4, num4); for (int j = 0; j < nbEBands; j++) { array5[0][j] += Inlines.HALF16(Inlines.SHL16(i, 10)); } if (num4 == 2) { for (int j = 0; j < nbEBands; j++) { array5[1][j] += Inlines.HALF16(Inlines.SHL16(i, 10)); } } tf_estimate = 3277; } if (i > 0 && enc.tell() + 3 <= num24) { enc.enc_bit_logp(compressed.Slice(compressed_ptr), num2, 3u); } int[][] array7 = Arrays.InitTwoDimensionalArray(num4, num14); Bands.normalise_bands(celtMode, array2, array7, array3, num25, num4, num13); int[] array8 = new int[nbEBands]; int tf_select; if (num20 >= 15 * num4 && num11 == 0 && complexity >= 2 && lfe == 0) { int num41 = ((num20 < 40) ? 12 : ((num20 < 60) ? 6 : ((num20 >= 100) ? 3 : 4))); num41 *= 2; tf_select = CeltCommon.tf_analysis(celtMode, num25, num2, array8, num41, array7, num14, i, out var _, tf_estimate, tf_chan); for (int j = num25; j < num12; j++) { array8[j] = array8[num25 - 1]; } } else { int tf_sum = 0; for (int j = 0; j < num12; j++) { array8[j] = num2; } tf_select = 0; } int[][] error = Arrays.InitTwoDimensionalArray(num4, nbEBands); QuantizeBands.quant_coarse_energy(celtMode, num11, num12, num25, array4, oldBandE, (uint)num24, error, enc, compressed.Slice(compressed_ptr), num4, i, num17, force_intra, ref delayedIntra, (complexity >= 4) ? 1 : 0, loss_rate, lfe); CeltCommon.tf_encode(num11, num12, num2, array8, i, tf_select, enc, compressed.Slice(compressed_ptr)); if (enc.tell() + 4 <= num24) { if (lfe != 0) { tapset_decision = 0; spread_decision = 2; } else if (num != 0 || complexity < 3 || num17 < 10 * num4 || num11 != 0) { if (complexity == 0) { spread_decision = 0; } else { spread_decision = 2; } } else { spread_decision = Bands.spreading_decision(celtMode, array7, ref tonal_average, spread_decision, ref hf_average, ref tapset_decision, (num28 != 0 && num == 0) ? 1 : 0, num25, num4, num13); } enc.enc_icdf(compressed.Slice(compressed_ptr), spread_decision, Tables.spread_icdf, 5u); } int[] array9 = new int[nbEBands]; int tot_boost_; int maxDepth = CeltCommon.dynalloc_analysis(array4, array5, nbEBands, num11, num12, num4, array9, lsb_depth, celtMode.logN, num2, vbr, constrained_vbr, eBands, i, num20, out tot_boost_, lfe, array6); if (lfe != 0) { array9[0] = Inlines.IMIN(8, num20 / 3); } int[] array10 = new int[nbEBands]; CeltCommon.init_caps(celtMode, array10, i, num4); int num42 = 6; num24 <<= 3; int num43 = 0; num15 = (int)enc.tell_frac(); for (int j = num11; j < num12; j++) { int num44 = num4 * (eBands[j + 1] - eBands[j]) << i; int num45 = Inlines.IMIN(num44 << 3, Inlines.IMAX(48, num44)); int num46 = num42; int num47 = 0; int num48 = 0; while (num15 + (num46 << 3) < num24 - num43 && num47 < array10[j]) { int num49 = ((num48 < array9[j]) ? 1 : 0); enc.enc_bit_logp(compressed.Slice(compressed_ptr), num49, (uint)num46); num15 = (int)enc.tell_frac(); if (num49 == 0) { break; } num47 += num45; num43 += num45; num46 = 1; num48++; } if (num48 != 0) { num42 = Inlines.IMAX(2, num42 - 1); } array9[j] = num47; } if (num4 == 2) { if (i != 0) { dual_stereo = CeltCommon.stereo_analysis(celtMode, array7, i); } intensity = Bands.hysteresis_decision(num10 / 1000, Tables.intensity_thresholds, Tables.intensity_histeresis, 21, intensity); intensity = Inlines.IMIN(num12, Inlines.IMAX(num11, intensity)); } int num50 = 5; if (num15 + 48 <= num24 - num43) { num50 = ((lfe == 0) ? CeltCommon.alloc_trim_analysis(celtMode, array7, array4, num12, i, num4, analysis, ref stereo_saving, tf_estimate, intensity, surround_trim) : 5); enc.enc_icdf(compressed.Slice(compressed_ptr), num50, Tables.trim_icdf, 7u); num15 = (int)enc.tell_frac(); } if (num19 > 0) { int num51 = celtMode.maxLM - i; nbCompressedBytes = Inlines.IMIN(nbCompressedBytes, 1275 >> 3 - i); int num52 = num19 - (40 * num4 + 20 << 3); if (constrained_vbr != 0) { num52 += vbr_offset >> num51; } int num53 = CeltCommon.compute_vbr(celtMode, analysis, num52, i, num10, lastCodedBands, num4, intensity, constrained_vbr, stereo_saving, tot_boost_, tf_estimate, pitch_change, maxDepth, variable_duration, lfe, (energy_mask != null) ? 1 : 0, surround_masking, num9); num53 += num15; int a3 = (num15 + num43 + 64 - 1 >> 6) + 2 - num16; num17 = num53 + 32 >> 6; num17 = Inlines.IMAX(a3, num17); num17 = Inlines.IMIN(nbCompressedBytes, num17 + num16) - num16; int num54 = num53 - num19; num53 = num17 << 6; if (num7 != 0) { num17 = 2; num53 = 128; num54 = 0; } int a4; if (vbr_count < 970) { vbr_count++; a4 = Inlines.celt_rcp(Inlines.SHL32(vbr_count + 20, 16)); } else { a4 = 33; } if (constrained_vbr != 0) { vbr_reservoir += num53 - num19; } if (constrained_vbr != 0) { vbr_drift += Inlines.MULT16_32_Q15(a4, num54 * (1 << num51) - vbr_offset - vbr_drift); vbr_offset = -vbr_drift; } if (constrained_vbr != 0 && vbr_reservoir < 0) { int num55 = -vbr_reservoir / 64; num17 += ((num7 == 0) ? num55 : 0); vbr_reservoir = 0; } nbCompressedBytes = Inlines.IMIN(nbCompressedBytes, num17 + num16); enc.enc_shrink(compressed.Slice(compressed_ptr), (uint)nbCompressedBytes); } int[] array11 = new int[nbEBands]; int[] pulses = new int[nbEBands]; int[] fine_priority = new int[nbEBands]; int num56 = (nbCompressedBytes * 8 << 3) - (int)enc.tell_frac() - 1; int num57 = ((num2 != 0 && i >= 2 && num56 >= i + 2 << 3) ? 8 : 0); num56 -= num57; int signalBandwidth = num12 - 1; if (analysis.valid != 0) { int b = ((num10 < 32000 * num4) ? 13 : ((num10 < 48000 * num4) ? 16 : ((num10 < 60000 * num4) ? 18 : ((num10 >= 80000 * num4) ? 20 : 19)))); signalBandwidth = Inlines.IMAX(analysis.bandwidth, b); } if (lfe != 0) { signalBandwidth = 1; } int balance; int num58 = Rate.compute_allocation_encode(celtMode, num11, num12, array9, array10, num50, ref intensity, ref dual_stereo, num56, out balance, pulses, array11, fine_priority, num4, i, enc, compressed.Slice(compressed_ptr), lastCodedBands, signalBandwidth); if (lastCodedBands != 0) { lastCodedBands = Inlines.IMIN(lastCodedBands + 1, Inlines.IMAX(lastCodedBands - 1, num58)); } else { lastCodedBands = num58; } QuantizeBands.quant_fine_energy(celtMode, num11, num12, oldBandE, error, array11, enc, compressed.Slice(compressed_ptr), num4); byte[] collapse_masks = new byte[num4 * nbEBands]; Bands.quant_all_bands_encode(1, celtMode, num11, num12, array7[0], (num4 == 2) ? array7[1] : null, collapse_masks, array3, pulses, num, spread_decision, dual_stereo, intensity, array8, nbCompressedBytes * 64 - num57, balance, enc, compressed.Slice(compressed_ptr), i, num58, ref rng); if (num57 > 0) { num6 = ((consec_transient < 2) ? 1 : 0); enc.enc_bits(compressed.Slice(compressed_ptr), (uint)num6, 1u); } QuantizeBands.quant_energy_finalise(celtMode, num11, num12, oldBandE, error, array11, fine_priority, nbCompressedBytes * 8 - enc.tell(), enc, compressed.Slice(compressed_ptr), num4); if (num7 != 0) { for (int j = 0; j < nbEBands; j++) { oldBandE[0][j] = -28672; } if (num4 == 2) { for (int j = 0; j < nbEBands; j++) { oldBandE[1][j] = -28672; } } } prefilter_period = pitch; prefilter_gain = gain; prefilter_tapset = num5; if (num3 == 2 && num4 == 1) { Arrays.MemCopy(oldBandE[0], 0, oldBandE[1], 0, nbEBands); } if (num2 == 0) { Arrays.MemCopy(oldLogE[0], 0, oldLogE2[0], 0, nbEBands); Arrays.MemCopy(oldBandE[0], 0, oldLogE[0], 0, nbEBands); if (num3 == 2) { Arrays.MemCopy(oldLogE[1], 0, oldLogE2[1], 0, nbEBands); Arrays.MemCopy(oldBandE[1], 0, oldLogE[1], 0, nbEBands); } } else { for (int j = 0; j < nbEBands; j++) { oldLogE[0][j] = Inlines.MIN16(oldLogE[0][j], oldBandE[0][j]); } if (num3 == 2) { for (int j = 0; j < nbEBands; j++) { oldLogE[1][j] = Inlines.MIN16(oldLogE[1][j], oldBandE[1][j]); } } } num26 = 0; do { for (int j = 0; j < num11; j++) { oldBandE[num26][j] = 0; oldLogE[num26][j] = (oldLogE2[num26][j] = -28672); } for (int j = num12; j < nbEBands; j++) { oldBandE[num26][j] = 0; oldLogE[num26][j] = (oldLogE2[num26][j] = -28672); } } while (++num26 < num3); if (num2 != 0 || num8 != 0) { consec_transient++; } else { consec_transient = 0; } rng = enc.rng; enc.enc_done(compressed.Slice(compressed_ptr)); if (enc.get_error() != 0) { return -3; } return nbCompressedBytes; } internal void SetComplexity(int value) { if (value < 0 || value > 10) { throw new ArgumentException("Complexity must be between 0 and 10 inclusive"); } complexity = value; } internal void SetStartBand(int value) { if (value < 0 || value >= mode.nbEBands) { throw new ArgumentException("Start band above max number of ebands (or negative)"); } start = value; } internal void SetEndBand(int value) { if (value < 1 || value > mode.nbEBands) { throw new ArgumentException("End band above max number of ebands (or less than 1)"); } end = value; } internal void SetPacketLossPercent(int value) { if (value < 0 || value > 100) { throw new ArgumentException("Packet loss must be between 0 and 100"); } loss_rate = value; } internal void SetPrediction(int value) { if (value < 0 || value > 2) { throw new ArgumentException("CELT prediction mode must be 0, 1, or 2"); } disable_pf = ((value <= 1) ? 1 : 0); force_intra = ((value == 0) ? 1 : 0); } internal void SetVBRConstraint(bool value) { constrained_vbr = (value ? 1 : 0); } internal void SetVBR(bool value) { vbr = (value ? 1 : 0); } internal void SetBitrate(int value) { if (value <= 500 && value != -1) { throw new ArgumentException("Bitrate out of range"); } value = Inlines.IMIN(value, 260000 * channels); bitrate = value; } internal void SetChannels(int value) { if (value < 1 || value > 2) { throw new ArgumentException("Channel count must be 1 or 2"); } stream_channels = value; } internal void SetLSBDepth(int value) { if (value < 8 || value > 24) { throw new ArgumentException("Bit depth must be between 8 and 24"); } lsb_depth = value; } internal int GetLSBDepth() { return lsb_depth; } internal void SetExpertFrameDuration(OpusFramesize value) { variable_duration = value; } internal void SetSignalling(int value) { signalling = value; } internal void SetAnalysis(AnalysisInfo value) { if (value == null) { throw new ArgumentNullException("AnalysisInfo"); } analysis.Assign(value); } internal CeltMode GetMode() { return mode; } internal uint GetFinalRange() { return rng; } internal void SetLFE(int value) { lfe = value; } internal void SetEnergyMask(int[] value) { energy_mask = value; } } internal class CeltMode { internal int Fs; internal int overlap; internal int nbEBands; internal int effEBands; internal int[] preemph = new int[4]; internal short[] eBands; internal int maxLM; internal int nbShortMdcts; internal int shortMdctSize; internal int nbAllocVectors; internal byte[] allocVectors; internal short[] logN; internal int[] window; internal MDCTLookup mdct = new MDCTLookup(); internal PulseCache cache = new PulseCache(); internal static readonly CeltMode mode48000_960_120 = new CeltMode { Fs = 48000, overlap = 120, nbEBands = 21, effEBands = 21, preemph = new int[4] { 27853, 0, 4096, 8192 }, eBands = Tables.eband5ms, maxLM = 3, nbShortMdcts = 8, shortMdctSize = 120, nbAllocVectors = 11, allocVectors = Tables.band_allocation, logN = Tables.logN400, window = Tables.window120, mdct = new MDCTLookup { n = 1920, maxshift = 3, kfft = new FFTState[4] { Tables.fft_state48000_960_0, Tables.fft_state48000_960_1, Tables.fft_state48000_960_2, Tables.fft_state48000_960_3 }, trig = Tables.mdct_twiddles960 }, cache = new PulseCache { size = 392, index = Tables.cache_index50, bits = Tables.cache_bits50, caps = Tables.cache_caps50 } }; private CeltMode() { } } internal class FFTState { internal int nfft; internal short scale; internal int scale_shift; internal int shift; internal short[] factors = new short[16]; internal short[] bitrev; internal short[] twiddles; } internal class MDCTLookup { internal int n; internal int maxshift; internal FFTState[] kfft = new FFTState[4]; internal short[] trig; internal MDCTLookup() { } } internal class PulseCache { internal int size; internal short[] index; internal byte[] bits; internal byte[] caps; internal void Reset() { size = 0; index = null; bits = null; caps = null; } } } namespace Concentus.Celt.Enums { internal static class Spread { internal const int SPREAD_NONE = 0; internal const int SPREAD_LIGHT = 1; internal const int SPREAD_NORMAL = 2; internal const int SPREAD_AGGRESSIVE = 3; } }