Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ValheimVOIP v0.1.1
ValheimVoip.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Concentus.Celt; using Concentus.Celt.Structs; using Concentus.Common; using Concentus.Common.CPlusPlus; using Concentus.Enums; using Concentus.Silk; using Concentus.Silk.Enums; using Concentus.Silk.Structs; using Concentus.Structs; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace ValheimVoip { internal sealed class VoiceCapture : MonoBehaviour { private const int MicrophoneBufferSeconds = 1; private VoiceNetwork _network; private AudioClip _microphoneClip; private string _device; private int _lastPosition; private float[] _frameBuffer; private float[] _scratch; private readonly OpusVoiceCodec _codec = new OpusVoiceCodec(); public void Initialize(VoiceNetwork network) { _network = network; } private void Update() { if (!VoiceRuntimeSettings.Enabled || (Object)(object)ZNet.instance == (Object)null || !IsInWorld()) { StopMicrophone(); } else if (ShouldTransmit()) { EnsureMicrophone(); CaptureAvailableFrames(); } } private static bool IsInWorld() { return (Object)(object)Player.m_localPlayer != (Object)null && ZRoutedRpc.instance != null; } private static bool ShouldTransmit() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) return VoiceSettings.VoiceActivation.Value || Input.GetKey(VoiceSettings.PushToTalkKeyCode); } private void EnsureMicrophone() { if ((!((Object)(object)_microphoneClip != (Object)null) || !Microphone.IsRecording(_device)) && Microphone.devices.Length != 0) { _device = Microphone.devices[0]; int sampleRate = VoiceRuntimeSettings.SampleRate; _microphoneClip = Microphone.Start(_device, true, 1, sampleRate); _lastPosition = 0; int num = sampleRate * VoiceRuntimeSettings.FrameMilliseconds / 1000; _frameBuffer = new float[num]; _scratch = new float[_microphoneClip.samples]; } } private void StopMicrophone() { if (!((Object)(object)_microphoneClip == (Object)null)) { if (Microphone.IsRecording(_device)) { Microphone.End(_device); } _microphoneClip = null; _lastPosition = 0; } } private void CaptureAvailableFrames() { if ((Object)(object)_microphoneClip == (Object)null) { return; } int position = Microphone.GetPosition(_device); if (position >= 0 && position != _lastPosition) { int num = ((position > _lastPosition) ? (position - _lastPosition) : (_microphoneClip.samples - _lastPosition + position)); while (num >= _frameBuffer.Length) { ReadFrame(_lastPosition, _frameBuffer); _lastPosition = (_lastPosition + _frameBuffer.Length) % _microphoneClip.samples; num -= _frameBuffer.Length; TrySendFrame(_frameBuffer); } } } private void ReadFrame(int startPosition, float[] destination) { if (startPosition + destination.Length <= _microphoneClip.samples) { _microphoneClip.GetData(destination, startPosition); return; } _microphoneClip.GetData(_scratch, 0); for (int i = 0; i < destination.Length; i++) { destination[i] = _scratch[(startPosition + i) % _microphoneClip.samples]; } } private void TrySendFrame(float[] frame) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) if (!VoiceSettings.VoiceActivation.Value || !(AudioMath.Rms(frame, frame.Length) < VoiceSettings.VoiceActivationThreshold.Value)) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { VoicePacket voicePacket = new VoicePacket(); voicePacket.SpeakerId = localPlayer.GetPlayerID(); voicePacket.SpeakerPosition = ((Component)localPlayer).transform.position; voicePacket.SampleRate = VoiceRuntimeSettings.SampleRate; voicePacket.Samples = frame.Length; voicePacket.OpusPayload = _codec.Encode(frame, frame.Length, VoiceRuntimeSettings.SampleRate); VoicePacket packet = voicePacket; _network.Send(packet); } } } } internal sealed class VoiceClient { public void Send(VoicePacket packet) { if (ZRoutedRpc.instance == null || (Object)(object)ZNet.instance == (Object)null) { return; } if (ZNet.instance.IsServer()) { VoiceServer instance = VoiceServer.Instance; if ((Object)(object)instance != (Object)null) { instance.Relay(ZNet.GetUID(), packet); } return; } ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer != null) { ZRoutedRpc.instance.InvokeRoutedRPC(serverPeer.m_uid, "ValheimVoip_VoiceFrame", new object[1] { packet.ToPackage() }); } } public void ApplyServerSettings(long senderPeerId, ZPackage package) { if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer()) { return; } ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer == null || serverPeer.m_uid != senderPeerId) { VoiceLog.WarningRateLimited("voice-settings-unauthorized", "Ignored voice settings package from non-server peer " + senderPeerId + ".", 30f); return; } try { if (VoiceRuntimeSettings.ApplyServerPackage(package, out var summary)) { ValheimVoipPlugin.Log.LogInfo((object)("Applied server voice settings: " + summary)); } else { VoiceLog.InfoRateLimited("voice-settings-unchanged", "Received server voice settings: " + summary, 60f); } } catch (Exception ex) { VoiceLog.WarningRateLimited("voice-settings-malformed", "Dropped malformed voice settings package from server peer " + senderPeerId + ": " + ex.Message, 10f); } } public void OnRpcUnavailable() { VoiceRuntimeSettings.ClearServerSettings(); } } internal sealed class VoicePlayback : MonoBehaviour { private sealed class SpeakerPlayback { private readonly object _lock = new object(); private readonly Queue<float> _samples = new Queue<float>(); private readonly GameObject _sourceObject; private AudioClip _clip; private int _bufferedSamples; private int _sampleRate; private int _underflowEvents; private int _droppedSamples; private float _nextBufferLog; public readonly long SpeakerId; public readonly AudioSource Source; public readonly OpusVoiceCodec Codec = new OpusVoiceCodec(); public float LastPacketTime { get; private set; } private int BufferedSamples { get { lock (_lock) { return _bufferedSamples; } } } public SpeakerPlayback(long speakerId, GameObject sourceObject, int sampleRate) { SpeakerId = speakerId; _sourceObject = sourceObject; Source = sourceObject.AddComponent<AudioSource>(); Source.playOnAwake = false; Source.spatialBlend = 1f; Source.rolloffMode = (AudioRolloffMode)1; Source.dopplerLevel = 0f; EnsureSampleRate(sampleRate); } public void EnsureSampleRate(int sampleRate) { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown //IL_00d8: Expected O, but got Unknown sampleRate = Mathf.Max(8000, sampleRate); if (!((Object)(object)_clip != (Object)null) || _sampleRate != sampleRate) { _sampleRate = sampleRate; lock (_lock) { _samples.Clear(); _bufferedSamples = 0; } if (Source.isPlaying) { Source.Stop(); } _clip = AudioClip.Create("voip-stream-" + SpeakerId, _sampleRate, 1, _sampleRate, true, new PCMReaderCallback(OnAudioRead), new PCMSetPositionCallback(OnAudioSetPosition)); Source.clip = _clip; Source.loop = true; } } public void UpdateSource(Vector3 position) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) LastPacketTime = Time.time; ((Component)Source).transform.position = position; Source.maxDistance = VoiceRuntimeSettings.ProximityMeters; Source.minDistance = VoiceRuntimeSettings.FullVolumeMeters; Source.volume = VoiceSettings.PlaybackVolume.Value; } public void Enqueue(float[] decodedSamples) { if (decodedSamples == null || decodedSamples.Length == 0) { return; } int num = Mathf.Max(1, _sampleRate * VoiceSettings.EffectiveMaxJitterBufferMilliseconds / 1000); int num2 = 0; lock (_lock) { foreach (float item in decodedSamples) { _samples.Enqueue(item); } _bufferedSamples += decodedSamples.Length; while (_bufferedSamples > num && _samples.Count > 0) { _samples.Dequeue(); _bufferedSamples--; num2++; } _droppedSamples += num2; } } public void UpdatePlayback() { int num = Mathf.Max(1, _sampleRate * VoiceSettings.EffectiveJitterBufferMilliseconds / 1000); if (!Source.isPlaying && BufferedSamples >= num) { Source.Play(); VoiceLog.InfoRateLimited("voice-jitter-start-" + SpeakerId, "Started jitter-buffered playback for " + SpeakerId + " with " + BufferedSamples + " queued samples.", 10f); } if (Time.time >= _nextBufferLog) { int underflowEvents; int droppedSamples; lock (_lock) { underflowEvents = _underflowEvents; droppedSamples = _droppedSamples; _underflowEvents = 0; _droppedSamples = 0; } _nextBufferLog = Time.time + 10f; if (underflowEvents > 0) { ValheimVoipPlugin.Log.LogWarning((object)("Voice jitter buffer underflow for " + SpeakerId + " (" + underflowEvents + " silent samples in the last window).")); } if (droppedSamples > 0) { ValheimVoipPlugin.Log.LogWarning((object)("Voice jitter buffer dropped " + droppedSamples + " old samples for " + SpeakerId + " to stay within the max buffer.")); } } } public void Destroy() { if ((Object)(object)_sourceObject != (Object)null) { Object.Destroy((Object)(object)_sourceObject); } } private void OnAudioRead(float[] data) { lock (_lock) { for (int i = 0; i < data.Length; i++) { if (_samples.Count > 0) { data[i] = _samples.Dequeue(); _bufferedSamples--; } else { data[i] = 0f; _underflowEvents++; } } } } private void OnAudioSetPosition(int position) { } } private const float SpeakerIdleDestroySeconds = 10f; private readonly Dictionary<long, SpeakerPlayback> _speakers = new Dictionary<long, SpeakerPlayback>(); public void Play(VoicePacket packet) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (packet.OpusPayload == null || packet.OpusPayload.Length == 0 || packet.Samples <= 0) { return; } SpeakerPlayback speaker = GetSpeaker(packet.SpeakerId, packet.SampleRate); speaker.UpdateSource(packet.SpeakerPosition); try { speaker.Enqueue(speaker.Codec.Decode(packet.OpusPayload, packet.Samples, packet.SampleRate)); } catch (Exception ex) { VoiceLog.WarningRateLimited("voice-decode-failed-" + packet.SpeakerId, "Dropped undecodable voice frame from " + packet.SpeakerId + ": " + ex.Message, 5f); } } private void Update() { List<long> list = null; foreach (KeyValuePair<long, SpeakerPlayback> speaker in _speakers) { speaker.Value.UpdatePlayback(); if (Time.time - speaker.Value.LastPacketTime > 10f) { if (list == null) { list = new List<long>(); } list.Add(speaker.Key); } } if (list == null) { return; } foreach (long item in list) { if (_speakers.TryGetValue(item, out var value)) { value.Destroy(); _speakers.Remove(item); } } } private SpeakerPlayback GetSpeaker(long speakerId, int sampleRate) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown if (_speakers.TryGetValue(speakerId, out var value) && value != null) { value.EnsureSampleRate(sampleRate); return value; } GameObject val = new GameObject("VOIP Speaker " + speakerId); Object.DontDestroyOnLoad((Object)(object)val); value = new SpeakerPlayback(speakerId, val, sampleRate); _speakers[speakerId] = value; return value; } private void OnDestroy() { foreach (SpeakerPlayback value in _speakers.Values) { value.Destroy(); } _speakers.Clear(); } } internal sealed class VoiceServer : MonoBehaviour { private const float SettingsBroadcastInterval = 10f; private float _nextSettingsBroadcast; internal static VoiceServer Instance { get; private set; } private void Awake() { Instance = this; } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void Update() { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && Time.time >= _nextSettingsBroadcast) { BroadcastServerSettings(); _nextSettingsBroadcast = Time.time + 10f; } } public void Relay(long senderPeerId, VoicePacket packet) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null || ZRoutedRpc.instance == null) { return; } float proximityMeters = VoiceRuntimeSettings.ProximityMeters; float num = proximityMeters * proximityMeters; foreach (ZNetPeer connectedPeer in ZNet.instance.GetConnectedPeers()) { if (connectedPeer != null && connectedPeer.m_uid != senderPeerId) { Vector3 val = connectedPeer.GetRefPos() - packet.SpeakerPosition; if (!(((Vector3)(ref val)).sqrMagnitude > num)) { ZRoutedRpc.instance.InvokeRoutedRPC(connectedPeer.m_uid, "ValheimVoip_VoiceFrame", new object[1] { packet.ToPackage() }); } } } } private static void BroadcastServerSettings() { if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "ValheimVoip_Settings", new object[1] { VoiceRuntimeSettings.CreateServerPackage() }); VoiceLog.InfoRateLimited("voice-settings-broadcast", "Broadcasting server voice settings: " + VoiceRuntimeSettings.CreateServerSummary(), 60f); } } } internal static class AudioMath { public static float Rms(float[] samples, int count) { if (count <= 0) { return 0f; } double num = 0.0; for (int i = 0; i < count; i++) { num += (double)(samples[i] * samples[i]); } return (float)Math.Sqrt(num / (double)count); } } internal sealed class OpusVoiceCodec { private const int Channels = 1; private const int MaxOpusPacketBytes = 1275; private OpusEncoder _encoder; private OpusDecoder _decoder; private int _encoderSampleRate; private int _decoderSampleRate; private int _bitrate; private int _complexity; private short[] _encodeBuffer; private short[] _decodeBuffer; private byte[] _packetBuffer; public byte[] Encode(float[] samples, int count, int sampleRate) { EnsureEncoder(sampleRate, count); for (int i = 0; i < count; i++) { float num = Math.Max(-1f, Math.Min(1f, samples[i])); _encodeBuffer[i] = (short)Math.Round(num * 32767f); } int num2 = _encoder.Encode(_encodeBuffer, 0, count, _packetBuffer, 0, _packetBuffer.Length); byte[] array = new byte[num2]; Buffer.BlockCopy(_packetBuffer, 0, array, 0, num2); return array; } public float[] Decode(byte[] payload, int samples, int sampleRate) { EnsureDecoder(sampleRate, samples); int num = _decoder.Decode(payload, 0, payload.Length, _decodeBuffer, 0, samples); float[] array = new float[num]; for (int i = 0; i < num; i++) { array[i] = (float)_decodeBuffer[i] / 32768f; } return array; } private void EnsureEncoder(int sampleRate, int frameSamples) { int opusBitrate = VoiceRuntimeSettings.OpusBitrate; int opusComplexity = VoiceRuntimeSettings.OpusComplexity; if (_encoder == null || _encoderSampleRate != sampleRate || _bitrate != opusBitrate || _complexity != opusComplexity) { _encoder = new OpusEncoder(sampleRate, 1, OpusApplication.OPUS_APPLICATION_VOIP); _encoder.Bitrate = opusBitrate; _encoder.Complexity = opusComplexity; _encoder.SignalType = OpusSignal.OPUS_SIGNAL_VOICE; _encoder.UseVBR = true; _encoder.UseConstrainedVBR = true; _encoderSampleRate = sampleRate; _bitrate = opusBitrate; _complexity = opusComplexity; } if (_encodeBuffer == null || _encodeBuffer.Length < frameSamples) { _encodeBuffer = new short[frameSamples]; } if (_packetBuffer == null) { _packetBuffer = new byte[1275]; } } private void EnsureDecoder(int sampleRate, int frameSamples) { if (_decoder == null || _decoderSampleRate != sampleRate) { _decoder = new OpusDecoder(sampleRate, 1); _decoderSampleRate = sampleRate; } if (_decodeBuffer == null || _decodeBuffer.Length < frameSamples) { _decodeBuffer = new short[frameSamples]; } } } [BepInPlugin("de.valheim.voip", "Valheim VOIP", "0.1.0")] public sealed class ValheimVoipPlugin : BaseUnityPlugin { public const string ModGuid = "de.valheim.voip"; public const string ModName = "Valheim VOIP"; public const string ModVersion = "0.1.0"; private GameObject _runnerObject; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; VoiceSettings.Bind(((BaseUnityPlugin)this).Config); _runnerObject = new GameObject("Valheim VOIP"); Object.DontDestroyOnLoad((Object)(object)_runnerObject); VoiceNetwork voiceNetwork = _runnerObject.AddComponent<VoiceNetwork>(); VoiceServer server = _runnerObject.AddComponent<VoiceServer>(); VoiceClient client = new VoiceClient(); VoicePlayback playback = _runnerObject.AddComponent<VoicePlayback>(); VoiceCapture voiceCapture = _runnerObject.AddComponent<VoiceCapture>(); voiceNetwork.Initialize(client, server, playback); voiceCapture.Initialize(voiceNetwork); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Valheim VOIP 0.1.0 loaded"); } private void OnDestroy() { if ((Object)(object)_runnerObject != (Object)null) { Object.Destroy((Object)(object)_runnerObject); } } } internal static class VoiceLog { private static readonly Dictionary<string, float> NextLogTimeByKey = new Dictionary<string, float>(); public static void InfoRateLimited(string key, string message, float intervalSeconds) { if (ShouldLog(key, intervalSeconds)) { ValheimVoipPlugin.Log.LogInfo((object)message); } } public static void WarningRateLimited(string key, string message, float intervalSeconds) { if (ShouldLog(key, intervalSeconds)) { ValheimVoipPlugin.Log.LogWarning((object)message); } } private static bool ShouldLog(string key, float intervalSeconds) { float time = Time.time; if (NextLogTimeByKey.TryGetValue(key, out var value) && time < value) { return false; } NextLogTimeByKey[key] = time + Mathf.Max(1f, intervalSeconds); return true; } } internal sealed class VoiceNetwork : MonoBehaviour { internal const string VoiceFrameRpcName = "ValheimVoip_VoiceFrame"; internal const string SettingsRpcName = "ValheimVoip_Settings"; private VoiceClient _client; private VoiceServer _server; private VoicePlayback _playback; private bool _registered; private ZRoutedRpc _registeredRpc; public void Initialize(VoiceClient client, VoiceServer server, VoicePlayback playback) { _client = client; _server = server; _playback = playback; } private void Update() { if (ZRoutedRpc.instance == null) { _registered = false; _registeredRpc = null; if (_client != null) { _client.OnRpcUnavailable(); } } else if (!_registered || _registeredRpc != ZRoutedRpc.instance) { ZRoutedRpc.instance.Register<ZPackage>("ValheimVoip_VoiceFrame", (Action<long, ZPackage>)OnVoiceFrame); ZRoutedRpc.instance.Register<ZPackage>("ValheimVoip_Settings", (Action<long, ZPackage>)OnSettings); _registered = true; _registeredRpc = ZRoutedRpc.instance; ValheimVoipPlugin.Log.LogInfo((object)"Voice RPC registered"); } } public void Send(VoicePacket packet) { _client.Send(packet); } private void OnVoiceFrame(long senderPeerId, ZPackage package) { if (!VoiceRuntimeSettings.Enabled) { return; } VoicePacket voicePacket; try { voicePacket = VoicePacket.FromPackage(package); } catch (Exception ex) { VoiceLog.WarningRateLimited("voice-packet-malformed-" + senderPeerId, "Dropped malformed voice packet from peer " + senderPeerId + ": " + ex.Message, 5f); return; } if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { _server.Relay(senderPeerId, voicePacket); if ((Object)(object)Player.m_localPlayer != (Object)null && voicePacket.SpeakerId != Player.m_localPlayer.GetPlayerID()) { _playback.Play(voicePacket); } } else if (!((Object)(object)Player.m_localPlayer != (Object)null) || voicePacket.SpeakerId != Player.m_localPlayer.GetPlayerID()) { _playback.Play(voicePacket); } } private void OnSettings(long senderPeerId, ZPackage package) { _client.ApplyServerSettings(senderPeerId, package); } } internal sealed class VoicePacket { public long SpeakerId; public Vector3 SpeakerPosition; public int SampleRate; public int Samples; public byte[] OpusPayload; public ZPackage ToPackage() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_0016: Unknown result type (might be due to invalid IL or missing references) ZPackage val = new ZPackage(); val.Write(SpeakerId); val.Write(SpeakerPosition); val.Write(SampleRate); val.Write(Samples); val.Write(OpusPayload); return val; } public static VoicePacket FromPackage(ZPackage package) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) VoicePacket voicePacket = new VoicePacket(); voicePacket.SpeakerId = package.ReadLong(); voicePacket.SpeakerPosition = package.ReadVector3(); voicePacket.SampleRate = package.ReadInt(); voicePacket.Samples = package.ReadInt(); voicePacket.OpusPayload = package.ReadByteArray(); return voicePacket; } } internal static class VoiceRuntimeSettings { private static bool _hasServerSettings; private static bool _enabled; private static float _proximityMeters; private static float _fullVolumeMeters; private static int _sampleRate; private static int _frameMilliseconds; private static int _opusBitrate; private static int _opusComplexity; private static string _lastAppliedSummary = string.Empty; public static bool Enabled => _hasServerSettings ? _enabled : VoiceSettings.Enabled.Value; public static float ProximityMeters => _hasServerSettings ? _proximityMeters : VoiceSettings.ProximityMeters.Value; public static float FullVolumeMeters => _hasServerSettings ? _fullVolumeMeters : VoiceSettings.FullVolumeMeters.Value; public static int SampleRate => _hasServerSettings ? _sampleRate : VoiceSettings.EffectiveSampleRate; public static int FrameMilliseconds => _hasServerSettings ? _frameMilliseconds : VoiceSettings.EffectiveFrameMilliseconds; public static int OpusBitrate => _hasServerSettings ? _opusBitrate : VoiceSettings.EffectiveOpusBitrate; public static int OpusComplexity => _hasServerSettings ? _opusComplexity : VoiceSettings.EffectiveOpusComplexity; public static void ClearServerSettings() { if (_hasServerSettings) { VoiceLog.InfoRateLimited("voice-settings-cleared", "Cleared server voice settings; using local config until the server syncs again.", 10f); } _hasServerSettings = false; _lastAppliedSummary = string.Empty; } public static ZPackage CreateServerPackage() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(1); val.Write(VoiceSettings.Enabled.Value); val.Write(VoiceSettings.ProximityMeters.Value); val.Write(VoiceSettings.FullVolumeMeters.Value); val.Write(VoiceSettings.EffectiveSampleRate); val.Write(VoiceSettings.EffectiveFrameMilliseconds); val.Write(VoiceSettings.EffectiveOpusBitrate); val.Write(VoiceSettings.EffectiveOpusComplexity); return val; } public static bool ApplyServerPackage(ZPackage package, out string summary) { summary = string.Empty; int num = package.ReadInt(); if (num != 1) { VoiceLog.WarningRateLimited("voice-settings-version", "Ignored unsupported voice settings package version " + num + ".", 30f); return false; } _enabled = package.ReadBool(); _proximityMeters = Mathf.Max(1f, package.ReadSingle()); _fullVolumeMeters = Mathf.Clamp(package.ReadSingle(), 0.1f, _proximityMeters); _sampleRate = SanitizeSampleRate(package.ReadInt()); _frameMilliseconds = SanitizeFrameMilliseconds(package.ReadInt()); _opusBitrate = Mathf.Clamp(package.ReadInt(), 6000, 128000); _opusComplexity = Mathf.Clamp(package.ReadInt(), 0, 10); _hasServerSettings = true; summary = CreateSummary(_enabled, _proximityMeters, _fullVolumeMeters, _sampleRate, _frameMilliseconds, _opusBitrate, _opusComplexity); bool result = summary != _lastAppliedSummary; _lastAppliedSummary = summary; return result; } public static string CreateServerSummary() { return CreateSummary(VoiceSettings.Enabled.Value, VoiceSettings.ProximityMeters.Value, VoiceSettings.FullVolumeMeters.Value, VoiceSettings.EffectiveSampleRate, VoiceSettings.EffectiveFrameMilliseconds, VoiceSettings.EffectiveOpusBitrate, VoiceSettings.EffectiveOpusComplexity); } private static string CreateSummary(bool enabled, float proximityMeters, float fullVolumeMeters, int sampleRate, int frameMilliseconds, int opusBitrate, int opusComplexity) { return "enabled=" + enabled + ", proximity=" + proximityMeters.ToString("0.#") + "m, fullVolume=" + fullVolumeMeters.ToString("0.#") + "m, sampleRate=" + sampleRate + ", frameMs=" + frameMilliseconds + ", bitrate=" + opusBitrate + ", complexity=" + opusComplexity; } private static int SanitizeSampleRate(int rate) { if (rate == 8000 || rate == 12000 || rate == 16000 || rate == 24000 || rate == 48000) { return rate; } return 16000; } private static int SanitizeFrameMilliseconds(int ms) { if (ms == 20 || ms == 40 || ms == 60) { return ms; } return 60; } } internal static class VoiceSettings { public static ConfigEntry<bool> Enabled { get; private set; } public static ConfigEntry<string> PushToTalkKey { get; private set; } public static ConfigEntry<bool> VoiceActivation { get; private set; } public static ConfigEntry<float> VoiceActivationThreshold { get; private set; } public static ConfigEntry<float> ProximityMeters { get; private set; } public static ConfigEntry<float> FullVolumeMeters { get; private set; } public static ConfigEntry<float> PlaybackVolume { get; private set; } public static ConfigEntry<int> SampleRate { get; private set; } public static ConfigEntry<int> FrameMilliseconds { get; private set; } public static ConfigEntry<int> JitterBufferMilliseconds { get; private set; } public static ConfigEntry<int> MaxJitterBufferMilliseconds { get; private set; } public static ConfigEntry<int> OpusBitrate { get; private set; } public static ConfigEntry<int> OpusComplexity { get; private set; } public static KeyCode PushToTalkKeyCode { get { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) KeyCode result; return (KeyCode)((!Enum.TryParse<KeyCode>(PushToTalkKey.Value, ignoreCase: true, out result)) ? 118 : ((int)result)); } } public static int EffectiveSampleRate { get { int value = SampleRate.Value; if (value == 8000 || value == 12000 || value == 16000 || value == 24000 || value == 48000) { return value; } return 16000; } } public static int EffectiveFrameMilliseconds { get { int value = FrameMilliseconds.Value; if (value == 20 || value == 40 || value == 60) { return value; } return 60; } } public static int EffectiveOpusComplexity => Mathf.Clamp(OpusComplexity.Value, 0, 10); public static int EffectiveOpusBitrate => Mathf.Clamp(OpusBitrate.Value, 6000, 128000); public static int EffectiveJitterBufferMilliseconds => Mathf.Clamp(JitterBufferMilliseconds.Value, 20, 1000); public static int EffectiveMaxJitterBufferMilliseconds => Mathf.Clamp(MaxJitterBufferMilliseconds.Value, EffectiveJitterBufferMilliseconds, 2000); public static void Bind(ConfigFile config) { Enabled = config.Bind<bool>("General", "Enabled", true, "Enable proximity voice chat."); PushToTalkKey = config.Bind<string>("Input", "PushToTalkKey", "V", "Unity KeyCode name used for push-to-talk."); VoiceActivation = config.Bind<bool>("Input", "VoiceActivation", false, "Transmit when the microphone level exceeds the configured threshold."); VoiceActivationThreshold = config.Bind<float>("Input", "VoiceActivationThreshold", 0.015f, "RMS threshold used when voice activation is enabled."); ProximityMeters = config.Bind<float>("Proximity", "ProximityMeters", 35f, "Maximum distance in meters for receiving voice."); FullVolumeMeters = config.Bind<float>("Proximity", "FullVolumeMeters", 6f, "Distance in meters where playback is still full volume."); PlaybackVolume = config.Bind<float>("Audio", "PlaybackVolume", 1f, "Master playback volume for received voice."); SampleRate = config.Bind<int>("Audio", "SampleRate", 16000, "Microphone sample rate. Opus supports 8000, 12000, 16000, 24000, and 48000."); FrameMilliseconds = config.Bind<int>("Audio", "FrameMilliseconds", 60, "Captured audio duration per network packet. Opus supports 20, 40, or 60 here."); JitterBufferMilliseconds = config.Bind<int>("Audio", "JitterBufferMilliseconds", 120, "Target playback buffer before received voice starts."); MaxJitterBufferMilliseconds = config.Bind<int>("Audio", "MaxJitterBufferMilliseconds", 500, "Maximum queued playback audio before old samples are dropped."); OpusBitrate = config.Bind<int>("Opus", "Bitrate", 24000, "Target Opus bitrate in bits per second."); OpusComplexity = config.Bind<int>("Opus", "Complexity", 5, "Opus encoder complexity from 0 to 10."); } } } namespace Concentus.Celt { internal static class Bands { public class band_ctx { public int encode; public CeltMode m; public int i; public int intensity; public int spread; public int tf_change; public EntropyCoder ec; public int remaining_bits; public int[][] bandE; public uint seed; } public class split_ctx { public int inv; public int imid; public int iside; public int delta; public int itheta; public 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; int num2 = num; num2 = 32767 - num2 + Inlines.FRAC_MUL16(num2, -7651 + Inlines.FRAC_MUL16(num2, 8277 + Inlines.FRAC_MUL16(-626, num2))); return 1 + num2; } 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; int num = m.shortMdctSize << LM; int num2 = 0; do { for (int i = 0; i < end; i++) { int num3 = 0; int num4 = 0; num3 = Inlines.celt_maxabs32(X[num2], eBands[i] << LM, eBands[i + 1] - eBands[i] << LM); if (num3 > 0) { int num5 = Inlines.celt_ilog2(num3) - 14 + ((m.logN[i] >> 3) + LM + 1 >> 1); int num6 = eBands[i] << LM; if (num5 > 0) { do { num4 = Inlines.MAC16_16(num4, Inlines.EXTRACT16(Inlines.SHR32(X[num2][num6], num5)), Inlines.EXTRACT16(Inlines.SHR32(X[num2][num6], num5))); } while (++num6 < eBands[i + 1] << LM); } else { do { num4 = Inlines.MAC16_16(num4, Inlines.EXTRACT16(Inlines.SHL32(X[num2][num6], -num5)), Inlines.EXTRACT16(Inlines.SHL32(X[num2][num6], -num5))); } while (++num6 < eBands[i + 1] << LM); } bandE[num2][i] = 1 + Inlines.VSHR32(Inlines.celt_sqrt(num4), -num5); } else { bandE[num2][i] = 1; } } } while (++num2 < 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 a = Inlines.VSHR32(bandE[num][num2], num3); int b = Inlines.EXTRACT16(Inlines.celt_rcp(Inlines.SHL32(a, 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, int[] freq, int freq_ptr, int[] 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 num3 = freq_ptr; int num4 = M * eBands[start]; for (int i = 0; i < M * eBands[start]; i++) { freq[num3++] = 0; } for (int i = start; i < end; i++) { int num5 = M * eBands[i]; int num6 = M * eBands[i + 1]; int num7 = Inlines.ADD16(bandLogE[bandLogE_ptr + i], Inlines.SHL16(Tables.eMeans[i], 6)); int num8 = 16 - (num7 >> 10); int b; if (num8 > 31) { num8 = 0; b = 0; } else { b = Inlines.celt_exp2_frac(num7 & 0x3FF); } if (num8 < 0) { if (num8 < -2) { b = 32767; num8 = -2; } do { freq[num3] = Inlines.SHR32(Inlines.MULT16_16(X[num4], b), -num8); } while (++num5 < num6); } else { do { freq[num3++] = Inlines.SHR32(Inlines.MULT16_16(X[num4++], b), num8); } while (++num5 < num6); } } 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; num2 = Inlines.SHL32(num2, 7 - num3 << 1); int a3 = Inlines.celt_rsqrt_norm(num2); 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], num7, num << LM, 32767); } } while (++num4 < C); } } internal static void intensity_stereo(CeltMode m, int[] X, int X_ptr, int[] 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(int[] X, int X_ptr, int[] 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(int[] X, int X_ptr, int[] Y, int Y_ptr, int mid, int N) { Kernels.dual_inner_prod(Y, Y_ptr, X, X_ptr, Y, Y_ptr, 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) { Array.Copy(X, X_ptr, Y, Y_ptr, N); return; } int num4 = Inlines.celt_ilog2(num2) >> 1; int num5 = Inlines.celt_ilog2(num3) >> 1; int x = Inlines.VSHR32(num2, num4 - 7 << 1); int a = Inlines.celt_rsqrt_norm(x); x = Inlines.VSHR32(num3, num5 - 7 << 1); int a2 = Inlines.celt_rsqrt_norm(x); 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[X_ptr + i]); int b = Y[Y_ptr + i]; X[X_ptr + i] = Inlines.EXTRACT16(Inlines.PSHR32(Inlines.MULT16_16(a, Inlines.SUB16(a3, b)), num4 + 1)); Y[Y_ptr + 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 = array; int[] array3 = 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(array3[j], array3[j]), num7); if (num8 < 2048) { array2[0]++; } if (num8 < 512) { array2[1]++; } if (num8 < 128) { array2[2]++; } } if (i > m.nbEBands - 4) { num3 += Inlines.celt_udiv(32 * (array2[1] + array2[0]), num7); } num5 = ((2 * array2[2] >= num7) ? 1 : 0) + ((2 * array2[1] >= num7) ? 1 : 0) + ((2 * array2[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; return (num < 80) ? 3 : ((num < 256) ? 2 : ((num < 384) ? 1 : 0)); } internal static void deinterleave_hadamard(int[] 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.Copy(array, 0, X, X_ptr, num); } internal static void interleave_hadamard(int[] 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.Copy(array, 0, X, X_ptr, num); } internal static void haar1(int[] 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(band_ctx ctx, split_ctx sctx, int[] X, int X_ptr, int[] 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; int encode = ctx.encode; 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; } if (encode != 0) { num = VQ.stereo_itheta(X, X_ptr, Y, Y_ptr, stereo, N); } int num5 = (int)ec.tell_frac(); if (num4 != 1) { if (encode != 0) { 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); if (encode != 0) { ec.encode((uint)((num7 <= num8) ? (num6 * num7) : (num7 - 1 - num8 + (num8 + 1) * num6)), (uint)((num7 <= num8) ? (num6 * (num7 + 1)) : (num7 - num8 + (num8 + 1) * num6)), ft); } else { int num9 = (int)ec.decode(ft); num7 = ((num9 >= (num8 + 1) * num6) ? (num8 + 1 + (num9 - (num8 + 1) * num6)) : (num9 / num6)); ec.dec_update((uint)((num7 <= num8) ? (num6 * num7) : (num7 - 1 - num8 + (num8 + 1) * num6)), (uint)((num7 <= num8) ? (num6 * (num7 + 1)) : (num7 - num8 + (num8 + 1) * num6)), ft); num = num7; } } else if (B0 > 1 || stereo != 0) { if (encode != 0) { ec.enc_uint((uint)num, (uint)(num4 + 1)); } else { num = (int)ec.dec_uint((uint)(num4 + 1)); } } else { int num9 = 1; int num10 = ((num4 >> 1) + 1) * ((num4 >> 1) + 1); if (encode != 0) { 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((uint)num11, (uint)(num11 + num9), (uint)num10); } else { int num11 = 0; int num12 = (int)ec.decode((uint)num10); if (num12 < (num4 >> 1) * ((num4 >> 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 * (num4 + 1) - Inlines.isqrt32((uint)(8 * (num10 - num12 - 1) + 1))) >> 1; num9 = num4 + 1 - num; num11 = num10 - ((num4 + 1 - num) * (num4 + 2 - num) >> 1); } ec.dec_update((uint)num11, (uint)(num11 + num9), (uint)num10); } } num = Inlines.celt_udiv(num * 16384, num4); if (encode != 0 && 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) { if (encode != 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) { if (encode != 0) { ec.enc_bit_logp(num2, 2u); } else { num2 = ec.dec_bit_logp(2u); } } else { num2 = 0; } num = 0; } int num13 = (int)ec.tell_frac() - num5; 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 = num2; sctx.imid = num14; sctx.iside = num15; sctx.delta = delta; sctx.itheta = num; sctx.qalloc = num13; } internal static uint quant_band_n1(band_ctx ctx, int[] X, int X_ptr, int[] Y, int Y_ptr, int b, int[] lowband_out, int lowband_out_ptr) { int num = ((ctx.encode == 0) ? 1 : 0); int[] array = X; int num2 = X_ptr; int encode = ctx.encode; EntropyCoder ec = ctx.ec; int num3 = ((Y != null) ? 1 : 0); int num4 = 0; do { int num5 = 0; if (ctx.remaining_bits >= 8) { if (encode != 0) { num5 = ((array[num2] < 0) ? 1 : 0); ec.enc_bits((uint)num5, 1u); } else { num5 = (int)ec.dec_bits(1u); } ctx.remaining_bits -= 8; b -= 8; } if (num != 0) { array[num2] = ((num5 != 0) ? (-16384) : 16384); } array = Y; num2 = Y_ptr; } while (++num4 < 1 + num3); if (lowband_out != null) { lowband_out[lowband_out_ptr] = Inlines.SHR16(X[X_ptr], 4); } return 1u; } internal static uint quant_partition(band_ctx ctx, int[] X, int X_ptr, int N, int b, int B, int[] lowband, int lowband_ptr, int LM, int gain, int fill) { int num = 0; int num2 = 0; int num3 = B; int num4 = 0; int num5 = 0; uint result = 0u; int num6 = ((ctx.encode == 0) ? 1 : 0); int num7 = 0; int encode = ctx.encode; CeltMode m = ctx.m; int i = ctx.i; int spread = ctx.spread; EntropyCoder ec = ctx.ec; byte[] bits = m.cache.bits; int num8 = m.cache.index[(LM + 1) * m.nbEBands + i]; if (LM != -1 && b > bits[num8 + bits[num8]] + 12 && N > 2) { split_ctx split_ctx = new split_ctx(); int lowband_ptr2 = 0; N >>= 1; num7 = X_ptr + N; LM--; if (B == 1) { fill = (fill & 1) | (fill << 1); } B = B + 1 >> 1; compute_theta(ctx, split_ctx, X, X_ptr, X, num7, N, ref b, B, num3, LM, 0, ref fill); num = split_ctx.imid; num2 = split_ctx.iside; int num9 = split_ctx.delta; int itheta = split_ctx.itheta; int qalloc = split_ctx.qalloc; num4 = num; num5 = num2; if (num3 > 1 && ((uint)itheta & 0x3FFFu) != 0) { num9 = ((itheta <= 8192) ? Inlines.IMIN(0, num9 + (N << 3 >> 5 - LM)) : (num9 - (num9 >> 4 - LM))); } int num10 = Inlines.IMAX(0, Inlines.IMIN(b, (b - num9) / 2)); int num11 = b - num10; ctx.remaining_bits -= qalloc; if (lowband != null) { lowband_ptr2 = lowband_ptr + N; } int remaining_bits = ctx.remaining_bits; if (num10 >= num11) { result = quant_partition(ctx, X, X_ptr, N, num10, B, lowband, lowband_ptr, LM, Inlines.MULT16_16_P15(gain, num4), fill); remaining_bits = num10 - (remaining_bits - ctx.remaining_bits); if (remaining_bits > 24 && itheta != 0) { num11 += remaining_bits - 24; } result |= quant_partition(ctx, X, num7, N, num11, B, lowband, lowband_ptr2, LM, Inlines.MULT16_16_P15(gain, num5), fill >> B) << (num3 >> 1); } else { result = quant_partition(ctx, X, num7, N, num11, B, lowband, lowband_ptr2, LM, Inlines.MULT16_16_P15(gain, num5), fill >> B) << (num3 >> 1); remaining_bits = num11 - (remaining_bits - ctx.remaining_bits); if (remaining_bits > 24 && itheta != 16384) { num10 += remaining_bits - 24; } result |= quant_partition(ctx, X, X_ptr, N, num10, B, lowband, lowband_ptr, LM, Inlines.MULT16_16_P15(gain, num4), fill); } } else { int num12 = Rate.bits2pulses(m, i, LM, b); int num13 = Rate.pulses2bits(m, i, LM, num12); ctx.remaining_bits -= num13; while (ctx.remaining_bits < 0 && num12 > 0) { ctx.remaining_bits += num13; num12--; num13 = Rate.pulses2bits(m, i, LM, num12); ctx.remaining_bits -= num13; } if (num12 != 0) { int k = Rate.get_pulses(num12); result = ((encode == 0) ? VQ.alg_unquant(X, X_ptr, N, k, spread, B, ec, gain) : VQ.alg_quant(X, X_ptr, N, k, spread, B, ec)); } else if (num6 != 0) { uint num14 = (uint)((int)(1L << B) - 1); fill &= (int)num14; if (fill == 0) { Arrays.MemSetWithOffset(X, 0, X_ptr, N); } else { if (lowband == null) { for (int j = 0; j < N; j++) { ctx.seed = celt_lcg_rand(ctx.seed); X[X_ptr + j] = (int)ctx.seed >> 20; } result = num14; } else { for (int j = 0; j < N; j++) { ctx.seed = celt_lcg_rand(ctx.seed); int num15 = 4; num15 = (((ctx.seed & 0x8000u) != 0) ? num15 : (-num15)); X[X_ptr + j] = lowband[lowband_ptr + j] + num15; } result = (uint)fill; } VQ.renormalise_vector(X, X_ptr, N, gain); } } } return result; } internal static uint quant_band(band_ctx ctx, int[] X, int X_ptr, int N, int b, int B, int[] lowband, int lowband_ptr, int LM, int[] lowband_out, int lowband_out_ptr, int gain, int[] 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 = ((ctx.encode == 0) ? 1 : 0); int encode = ctx.encode; int num6 = ctx.tf_change; int hadamard = ((num == 1) ? 1 : 0); n = Inlines.celt_udiv(n, B); if (N == 1) { return quant_band_n1(ctx, X, X_ptr, null, 0, b, lowband_out, lowband_out_ptr); } if (num6 > 0) { num3 = num6; } if (lowband_scratch != null && lowband != null && (num3 != 0 || ((n & 1) == 0 && num6 < 0) || num > 1)) { Array.Copy(lowband, lowband_ptr, lowband_scratch, lowband_scratch_ptr, N); lowband = lowband_scratch; lowband_ptr = lowband_scratch_ptr; } for (int i = 0; i < num3; i++) { if (encode != 0) { haar1(X, X_ptr, N >> i, 1 << i); } if (lowband != null) { 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 (encode != 0) { haar1(X, X_ptr, n, B); } if (lowband != null) { haar1(lowband, lowband_ptr, n, B); } fill |= fill << B; B <<= 1; n >>= 1; num2++; num6++; } num = B; int num7 = n; if (num > 1) { if (encode != 0) { deinterleave_hadamard(X, X_ptr, n >> num3, num << num3, hadamard); } if (lowband != null) { deinterleave_hadamard(lowband, lowband_ptr, n >> num3, num << num3, hadamard); } } num4 = quant_partition(ctx, 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 != null) { 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(band_ctx ctx, int[] X, int X_ptr, int[] Y, int Y_ptr, int N, int b, int B, int[] lowband, int lowband_ptr, int LM, int[] lowband_out, int lowband_out_ptr, int[] lowband_scratch, int lowband_scratch_ptr, int fill) { int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; uint num6 = 0u; int num7 = ((ctx.encode == 0) ? 1 : 0); split_ctx split_ctx = new split_ctx(); int encode = ctx.encode; EntropyCoder ec = ctx.ec; if (N == 1) { return quant_band_n1(ctx, X, X_ptr, Y, Y_ptr, b, lowband_out, lowband_out_ptr); } int fill2 = fill; compute_theta(ctx, split_ctx, X, X_ptr, Y, Y_ptr, N, ref b, B, B, LM, 1, ref fill); num3 = split_ctx.inv; num = split_ctx.imid; num2 = split_ctx.iside; int delta = split_ctx.delta; int itheta = split_ctx.itheta; int qalloc = split_ctx.qalloc; num4 = num; num5 = num2; if (N == 2) { int num8 = 0; int num9 = b; int num10 = 0; if (itheta != 0 && itheta != 16384) { num10 = 8; } num9 -= num10; int num11 = ((itheta > 8192) ? 1 : 0); ctx.remaining_bits -= qalloc + num10; int[] array; int num12; int[] array2; if (num11 != 0) { array = Y; num12 = Y_ptr; array2 = X; int num13 = X_ptr; } else { array = X; num12 = X_ptr; array2 = Y; int num13 = Y_ptr; } if (num10 != 0) { if (encode != 0) { num8 = ((array[num12] * array2[Y_ptr + 1] - array[num12 + 1] * array2[Y_ptr] < 0) ? 1 : 0); ec.enc_bits((uint)num8, 1u); } else { num8 = (int)ec.dec_bits(1u); } } num8 = 1 - 2 * num8; num6 = quant_band(ctx, array, num12, N, num9, B, lowband, lowband_ptr, LM, lowband_out, lowband_out_ptr, 32767, lowband_scratch, lowband_scratch_ptr, fill2); array2[Y_ptr] = -num8 * array[num12 + 1]; array2[Y_ptr + 1] = num8 * array[num12]; if (num7 != 0) { X[X_ptr] = Inlines.MULT16_16_Q15(num4, X[X_ptr]); X[X_ptr + 1] = Inlines.MULT16_16_Q15(num4, X[X_ptr + 1]); Y[Y_ptr] = Inlines.MULT16_16_Q15(num5, Y[Y_ptr]); Y[Y_ptr + 1] = Inlines.MULT16_16_Q15(num5, 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 num9 = Inlines.IMAX(0, Inlines.IMIN(b, (b - delta) / 2)); int num10 = b - num9; ctx.remaining_bits -= qalloc; int remaining_bits = ctx.remaining_bits; if (num9 >= num10) { num6 = quant_band(ctx, X, X_ptr, N, num9, B, lowband, lowband_ptr, LM, lowband_out, lowband_out_ptr, 32767, lowband_scratch, lowband_scratch_ptr, fill); remaining_bits = num9 - (remaining_bits - ctx.remaining_bits); if (remaining_bits > 24 && itheta != 0) { num10 += remaining_bits - 24; } num6 |= quant_band(ctx, Y, Y_ptr, N, num10, B, null, 0, LM, null, 0, num5, null, 0, fill >> B); } else { num6 = quant_band(ctx, Y, Y_ptr, N, num10, B, null, 0, LM, null, 0, num5, null, 0, fill >> B); remaining_bits = num10 - (remaining_bits - ctx.remaining_bits); if (remaining_bits > 24 && itheta != 16384) { num9 += remaining_bits - 24; } num6 |= quant_band(ctx, X, X_ptr, N, num9, B, lowband, lowband_ptr, LM, lowband_out, lowband_out_ptr, 32767, lowband_scratch, lowband_scratch_ptr, fill); } } if (num7 != 0) { if (N != 2) { stereo_merge(X, X_ptr, Y, Y_ptr, num4, N); } if (num3 != 0) { for (int i = Y_ptr; i < N + Y_ptr; i++) { Y[i] = (short)(-Y[i]); } } } return num6; } internal static void quant_all_bands(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, 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[] lowband_scratch = 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[] x = X_; int x_ptr = num4 * eBands[i]; int[] array2; if (Y_ != null) { array2 = Y_; num10 = num4 * eBands[i]; } else { array2 = 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) { x = array; x_ptr = 0; if (Y_ != null) { array2 = array; num10 = 0; } lowband_scratch = null; } if (i == end - 1) { lowband_scratch = 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(band_ctx, x, x_ptr, num13, num17 / 2, num5, (num9 != -1) ? array : null, num9, LM, (num12 != 0) ? null : array, num4 * eBands[i] - num6, 32767, lowband_scratch, lowband_scratch_ptr, (int)num21); num20 = quant_band(band_ctx, array2, num10, num13, num17 / 2, num5, (num9 != -1) ? array : null, num7 + num9, LM, (num12 != 0) ? null : array, num7 + (num4 * eBands[i] - num6), 32767, lowband_scratch, lowband_scratch_ptr, (int)num20); } else { num21 = ((array2 == null) ? quant_band(band_ctx, x, x_ptr, num13, num17, num5, (num9 != -1) ? array : null, num9, LM, (num12 != 0) ? null : array, num4 * eBands[i] - num6, 32767, lowband_scratch, lowband_scratch_ptr, (int)(num21 | num20)) : quant_band_stereo(band_ctx, x, x_ptr, array2, num10, num13, num17, num5, (num9 != -1) ? array : null, num9, LM, (num12 != 0) ? null : array, num4 * eBands[i] - num6, lowband_scratch, 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.enabled && 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.enabled && 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; int num2 = 0; tf_chan = 0; int[] array = new int[len]; int num3 = len / 2; for (int i = 0; i < C; i++) { int num4 = 0; int a = 0; int num5 = 0; for (int j = 0; j < len; j++) { int num6 = Inlines.SHR32(input[i][j], 12); int num7 = Inlines.ADD32(a, num6); a = num5 + num7 - Inlines.SHL32(num6, 1); num5 = num6 - Inlines.SHR32(num7, 1); array[j] = Inlines.EXTRACT16(Inlines.SHR32(num7, 2)); } Arrays.MemSet(array, 0, 12); int num8 = 0; num8 = 14 - Inlines.celt_ilog2(1 + Inlines.celt_maxabs32(array, 0, len)); if (num8 != 0) { for (int j = 0; j < len; j++) { array[j] = Inlines.SHL16(array[j], num8); } } int num9 = 0; a = 0; for (int j = 0; j < num3; j++) { int num10 = Inlines.PSHR32(Inlines.MULT16_16(array[2 * j], array[2 * j]) + Inlines.MULT16_16(array[2 * j + 1], array[2 * j + 1]), 16); num9 += num10; array[j] = a + Inlines.PSHR32(num10 - a, 4); a = array[j]; } a = 0; int a2 = 0; for (int j = num3 - 1; j >= 0; j--) { array[j] = a + Inlines.PSHR32(array[j] - a, 3); a = array[j]; a2 = Inlines.MAX16(a2, a); } num9 = Inlines.MULT16_16(Inlines.celt_sqrt(num9), Inlines.celt_sqrt(Inlines.MULT16_16(a2, num3 >> 1))); int b = Inlines.SHL32(num3, 20) / Inlines.ADD32(1, Inlines.SHR32(num9, 1)); num4 = 0; for (int j = 12; j < num3 - 5; j += 4) { int num11 = Inlines.MAX32(0, Inlines.MIN32(127, Inlines.MULT16_32_Q15(array[j] + 1, b))); num4 += inv_table[num11]; } num4 = 64 * num4 * 4 / (6 * (num3 - 17)); if (num4 > num2) { tf_chan = i; num2 = num4; } } num = ((num2 > 200) ? 1 : 0); int b2 = Inlines.MAX16(0, Inlines.celt_sqrt(27 * num2) - 42); tf_estimate = Inlines.celt_sqrt(Inlines.MAX32(0, Inlines.SHL32(Inlines.MULT16_16(113, Inlines.MIN16(163, b2)), 14) - 37312528)); return num; } 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(short[] pcmp, int pcmp_ptr, int[] 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 num2 = inp[inp_ptr + i]; inp[inp_ptr + i] = Inlines.SHL32(num2, 12) - num; num = Inlines.SHR32(Inlines.MULT16_16(a, num2), 3); } mem = num; } internal static void celt_preemphasis(short[] pcmp, int[] inp, int inp_ptr, int N, int CC, int upsample, int[] coef, BoxedValue<int> 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 num2 = inp[inp_ptr + i]; inp[inp_ptr + i] = Inlines.SHL32(num2, 12) - num; num = Inlines.SHR32(Inlines.MULT16_16(a, num2), 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); Array.Copy(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) { Array.Copy(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 num9; if (num11 < num12) { num9 = num11; array5[i] = 0; } else { num9 = num12; array5[i] = 1; } num11 = num7 + lambda; num12 = num8; int num10; if (num11 < num12) { num10 = num11; array6[i] = 0; } else { num10 = num12; array6[i] = 1; } num7 = num9 + Inlines.abs(array2[i] - 2 * Tables.tf_select_table[LM][4 * isTransient + 2 * num]); num8 = num10 + 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) { 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(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(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; for (int i = 0; i < 8; i++) { int a = Kernels.celt_inner_prod(X[0], m.eBands[i] << LM, X[1], 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++) { int a = Kernels.celt_inner_prod(X[0], m.eBands[i] << LM, X[1], m.eBands[i] << LM, m.eBands[i + 1] - m.eBands[i] << LM); num4 = Inlines.MIN16(num4, Inlines.ABS16(Inlines.EXTRACT16(Inlines.SHR32(a, 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.enabled && 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(int[] 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; num6 = num5; num5 = num3; num3 = num6; } 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(int[] 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<int>(2, nbEBands); int[] array2 = new int[C * nbEBands]; Arrays.MemSet(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, short[] 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 num7 = array2[num5 + i] + num4; num4 = Inlines.MULT16_32_Q15(a, num7); pcm[num6 + i * C] = Inlines.SAT16(Inlines.ADD32(pcm[num6 + i * C], Inlines.SIG2WORD16(num7))); } } else { for (int i = 0; i < N; i++) { int num7 = array2[num5 + i] + num4; if (array2[num5 + i] > 0 && num4 > 0 && num7 < 0) { num7 = int.MaxValue; num4 = int.MaxValue; } else { num4 = Inlines.MULT16_32_Q15(a, num7); } pcm[num6 + i * C] = Inlines.SIG2WORD16(num7); } } 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, short[] 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; Array.Copy(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 num5 = 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], num5, 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][num5 + 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 num6 = 0; do { Bands.denormalise_bands(mode, X[num6], array, 0, oldBandE, num6 * nbEBands, start, effEnd, num2, downsample, silence); for (int i = 0; i < num3; i++) { MDCT.clt_mdct_backward(mode.mdct, array, i, out_syn[num6], out_syn_ptrs[num6] + num4 * i, mode.window, overlap, shift, num3); } } while (++num6 < CC); } internal static void tf_decode(int start, int end, int isTransient, int[] tf_res, int LM, EntropyCoder dec) { 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((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(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(int[] y, int y_ptr, int[] 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(int[] y, int y_ptr, int[] 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) { if (x_ptr == y_ptr) { } return; } 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) { if (x_ptr == y_ptr) { } } else { 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 { public const int Q15ONE = 32767; public const float CELT_SIG_SCALE = 32768f; public const int SIG_SHIFT = 12; public const int NORM_SCALING = 16384; public const int DB_SHIFT = 10; public const int EPSILON = 1; public const int VERY_SMALL = 0; public const short VERY_LARGE16 = short.MaxValue; public const short Q15_ONE = short.MaxValue; public const int COMBFILTER_MAXPERIOD = 1024; public const int COMBFILTER_MINPERIOD = 15; public const int DECODE_BUFFER_SIZE = 2048; public const int BITALLOC_SIZE = 11; public const int MAX_PERIOD = 1024; public const int TOTAL_MODES = 1; public const int MAX_PSEUDO = 40; public const int LOG_MAX_PSEUDO = 6; public const int CELT_MAX_PULSES = 128; public const int MAX_FINE_BITS = 8; public const int FINE_OFFSET = 21; public const int QTHETA_OFFSET = 4; public const int QTHETA_OFFSET_TWOPHASE = 16; public const int PLC_PITCH_LAG_MAX = 720; public const int PLC_PITCH_LAG_MIN = 100; public const int LPC_ORDER = 24; } internal static class CeltLPC { internal static void celt_lpc(int[] _lpc, int[] ac, int p) { int num = ac[0]; int[] array = new int[p]; 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(array[j], ac[i - j]); } num2 += Inlines.SHR32(ac[i + 1], 3); int num3 = -Inlines.frac_div32(Inlines.SHL32(num2, 3), num); array[i] = Inlines.SHR32(num3, 3); for (int j = 0; j < i + 1 >> 1; j++) { int num4 = array[j]; int num5 = array[i - 1 - j]; array[j] = num4 + Inlines.MULT32_32_Q31(num3, num5); array[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(array[i], 16); } } internal static void celt_iir(int[] _x, int _x_ptr, int[] den, int[] _y, int _y_ptr, int N, int ord, int[] 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[_x_ptr + i]; int sum2 = _x[_x_ptr + i + 1]; int sum3 = _x[_x_ptr + i + 2]; int sum4 = _x[_x_ptr + i + 3]; Kernels.xcorr_kernel(array, array2, i, ref sum, ref sum2, ref sum3, ref sum4, ord); array2[i + ord] = -Inlines.ROUND16(sum, 12); _y[_y_ptr + i] = sum; sum2 = Inlines.MAC16_16(sum2, array2[i + ord], den[0]); array2[i + ord + 1] = -Inlines.ROUND16(sum2, 12); _y[_y_ptr + 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[_y_ptr + 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[_y_ptr + i + 3] = sum4; } for (; i < N; i++) { int num = _x[_x_ptr + 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[_y_ptr + i] = num; } for (i = 0; i < ord; i++) { mem[i] = _y[_y_ptr + N - i - 1]; } } } internal static class CeltPitchXCorr { internal static int pitch_xcorr(int[] _x, int[] _y, 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, _y, 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, 0, _y, i, len)); } return num; } internal static int pitch_xcorr(short[] _x, int _x_ptr, short[] _y, int _y_ptr, 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_ptr, _y, _y_ptr + 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, _x_ptr, _y, _y_ptr + i, len)); } return num; } internal static int pitch_xcorr(short[] _x, short[] _y, 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, 0, _y, 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, _y, 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 }; priva