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 VOIP v0.4.1
VOIP.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.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BreakoutMods.BreakoutNet; 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 VOIP { internal sealed class VoiceCapture : MonoBehaviour { private const int MicrophoneBufferSeconds = 1; private static readonly MethodInfo AudioClipGetData = typeof(AudioClip).GetMethod("GetData", new Type[2] { typeof(float[]), typeof(int) }); private VoiceNetwork _network; private AudioClip _microphoneClip; private string _device; private int _lastPosition; private int _sequence; private int _activeSampleRate; private int _activeFrameMilliseconds; private float _stopMicrophoneAt; 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()) { if (!VoiceSettings.VoiceActivation.Value && (Object)(object)_microphoneClip != (Object)null && Time.time >= _stopMicrophoneAt) { StopMicrophone(); } } else { _stopMicrophoneAt = Time.time + (float)VoiceSettings.EffectiveMicrophoneStopDelayMilliseconds / 1000f; 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() { int sampleRate = VoiceRuntimeSettings.SampleRate; int frameMilliseconds = VoiceRuntimeSettings.FrameMilliseconds; string text = ResolveMicrophoneDevice(); if (!((Object)(object)_microphoneClip != (Object)null) || !Microphone.IsRecording(_device) || _activeSampleRate != sampleRate || _activeFrameMilliseconds != frameMilliseconds || !(_device == text)) { StopMicrophone(); if (Microphone.devices.Length == 0) { VoiceLog.WarningRateLimited("voice-no-microphone", "VOIP could not find a microphone device.", 10f); return; } _device = text; _microphoneClip = Microphone.Start(_device, true, 1, sampleRate); _lastPosition = 0; _activeSampleRate = sampleRate; _activeFrameMilliseconds = frameMilliseconds; int num = sampleRate * frameMilliseconds / 1000; _frameBuffer = new float[num]; _scratch = new float[_microphoneClip.samples]; } } private static string ResolveMicrophoneDevice() { string value = VoiceSettings.MicrophoneDevice.Value; if (!string.IsNullOrWhiteSpace(value)) { string[] devices = Microphone.devices; foreach (string text in devices) { if (string.Equals(text, value, StringComparison.OrdinalIgnoreCase)) { return text; } } VoiceLog.WarningRateLimited("voice-microphone-missing-" + value, "Configured VOIP microphone device was not found: " + value, 10f); } return (Microphone.devices.Length > 0) ? Microphone.devices[0] : null; } private void StopMicrophone() { if (!((Object)(object)_microphoneClip == (Object)null)) { if (Microphone.IsRecording(_device)) { Microphone.End(_device); } _microphoneClip = null; _lastPosition = 0; _frameBuffer = null; _scratch = null; } } 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) { GetAudioClipData(_microphoneClip, destination, startPosition); return; } GetAudioClipData(_microphoneClip, _scratch, 0); for (int i = 0; i < destination.Length; i++) { destination[i] = _scratch[(startPosition + i) % _microphoneClip.samples]; } } private static void GetAudioClipData(AudioClip clip, float[] destination, int offsetSamples) { if (AudioClipGetData == null) { throw new MissingMethodException("UnityEngine.AudioClip.GetData(float[], int)"); } AudioClipGetData.Invoke(clip, new object[2] { destination, offsetSamples }); } private void TrySendFrame(float[] frame) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: 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.SenderPeerId = ZNet.GetUID(); voicePacket.Sequence = ++_sequence; 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); VoiceHud.MarkTransmitting(); } } } } internal sealed class VoiceClient { private readonly BreakoutModuleContext _context; public VoiceClient(BreakoutModuleContext context) { _context = context; } public void Send(VoicePacket packet) { if (BreakoutSide.IsInWorld && !((Object)(object)ZNet.instance == (Object)null)) { packet.SenderPeerId = ZNet.GetUID(); Client.SendToServer<VoicePacket>("voip.voice.frame", packet, (_context != null) ? _context.ModGuid : "com.breakoutmods.voip"); } } public void ApplyServerSettings(VoiceServerSettings settings) { try { string summary; bool flag = VoiceRuntimeSettings.ApplyServerSettings(settings, out summary); if (flag) { VOIPPlugin.Log.LogInfo((object)("Applied server voice settings: " + summary)); } else { VoiceLog.InfoRateLimited("voice-settings-unchanged", "Received server voice settings: " + summary, 60f); } if (_context != null) { _context.Events.Publish<VoiceSettingsAppliedEvent>(new VoiceSettingsAppliedEvent(flag, summary)); _context.Events.Publish<VoiceSettingsAppliedEvent>("voip.settings.applied", new VoiceSettingsAppliedEvent(flag, summary)); } } catch (Exception ex) { VoiceLog.WarningRateLimited("voice-settings-malformed", "Dropped malformed voice settings package from server: " + ex.Message, 10f); } } public void OnRpcUnavailable() { VoiceRuntimeSettings.ClearServerSettings(); } } internal sealed class VoiceHud : MonoBehaviour { private const float IndicatorSeconds = 0.35f; private static float _transmittingUntil; private static float _receivingUntil; public static void MarkTransmitting() { _transmittingUntil = Time.time + 0.35f; } public static void MarkReceiving() { _receivingUntil = Time.time + 0.35f; } private void Update() { if (!((Object)(object)Player.m_localPlayer == (Object)null) && VoiceRuntimeSettings.Enabled) { HandleInput(); } } private void OnGUI() { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Player.m_localPlayer == (Object)null) && VoiceRuntimeSettings.Enabled) { string text = null; if (VoiceMuteState.Deafened) { text = "VOIP DEAFENED"; } else if (VoiceMuteState.HasLastSpeaker && VoiceMuteState.IsMuted(VoiceMuteState.LastSpeakerId)) { text = "VOIP MUTED"; } else if (Time.time < _transmittingUntil) { text = "VOIP TX"; } else if (Time.time < _receivingUntil) { text = "VOIP RX"; } if (text != null) { GUI.Label(new Rect(20f, (float)Screen.height - 60f, 160f, 30f), text); } } } private static void HandleInput() { //IL_0001: 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) if (Input.GetKeyDown(VoiceSettings.ToggleDeafenKeyCode)) { VoiceMuteState.ToggleDeafen(); } if (Input.GetKeyDown(VoiceSettings.ToggleMuteLastSpeakerKeyCode)) { VoiceMuteState.ToggleLastSpeakerMute(); } } } internal static class VoiceMuteState { private static readonly HashSet<long> MutedSpeakerIds = new HashSet<long>(); private static string _loadedConfigValue; public static bool Deafened { get; private set; } public static long LastSpeakerId { get; private set; } public static bool HasLastSpeaker { get; private set; } public static void ToggleDeafen() { Deafened = !Deafened; VOIPPlugin.Log.LogInfo((object)("VOIP deafen " + (Deafened ? "enabled" : "disabled") + ".")); } public static void RememberSpeaker(long speakerId) { LastSpeakerId = speakerId; HasLastSpeaker = true; } public static void ToggleLastSpeakerMute() { LoadMutedSpeakers(); if (!HasLastSpeaker) { VoiceLog.InfoRateLimited("voice-mute-no-speaker", "VOIP has no recent speaker to mute.", 3f); return; } if (MutedSpeakerIds.Contains(LastSpeakerId)) { MutedSpeakerIds.Remove(LastSpeakerId); VOIPPlugin.Log.LogInfo((object)("Unmuted VOIP speaker " + LastSpeakerId + ".")); } else { MutedSpeakerIds.Add(LastSpeakerId); VOIPPlugin.Log.LogInfo((object)("Muted VOIP speaker " + LastSpeakerId + ".")); } SaveMutedSpeakers(); } public static bool IsMuted(long speakerId) { LoadMutedSpeakers(); return MutedSpeakerIds.Contains(speakerId); } private static void LoadMutedSpeakers() { string text = VoiceSettings.MutedSpeakerIds.Value ?? string.Empty; if (_loadedConfigValue == text) { return; } MutedSpeakerIds.Clear(); string[] array = text.Split(','); foreach (string text2 in array) { if (long.TryParse(text2.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { MutedSpeakerIds.Add(result); } } _loadedConfigValue = text; } private static void SaveMutedSpeakers() { string text = string.Join(",", (from id in MutedSpeakerIds orderby id select id.ToString(CultureInfo.InvariantCulture)).ToArray()); VoiceSettings.MutedSpeakerIds.Value = text; _loadedConfigValue = text; } } internal sealed class VoicePlayback : MonoBehaviour { private sealed class SpeakerPlayback { private readonly object _lock = new object(); private readonly GameObject _sourceObject; private float[] _ring; private AudioClip _clip; private int _readIndex; private int _writeIndex; private int _bufferedSamples; private int _sampleRate; private int _lastSequence; private bool _hasSequence; private int _underflowEvents; private int _droppedSamples; private int _lostPackets; 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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown //IL_00cc: Expected O, but got Unknown sampleRate = Mathf.Max(8000, sampleRate); if (!((Object)(object)_clip != (Object)null) || _sampleRate != sampleRate) { _sampleRate = sampleRate; lock (_lock) { ClearBuffer(); } 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 TrackSequence(int sequence) { lock (_lock) { if (_hasSequence && sequence > _lastSequence + 1) { _lostPackets += sequence - _lastSequence - 1; } _lastSequence = sequence; _hasSequence = true; } } public void Enqueue(float[] decodedSamples) { if (decodedSamples == null || decodedSamples.Length == 0) { return; } int capacity = Mathf.Max(1, _sampleRate * VoiceSettings.EffectiveMaxJitterBufferMilliseconds / 1000); int num = 0; lock (_lock) { EnsureRingCapacity(capacity); foreach (float num2 in decodedSamples) { if (_bufferedSamples == _ring.Length) { _readIndex = (_readIndex + 1) % _ring.Length; _bufferedSamples--; num++; } _ring[_writeIndex] = num2; _writeIndex = (_writeIndex + 1) % _ring.Length; _bufferedSamples++; } _droppedSamples += num; } } 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; int lostPackets; lock (_lock) { underflowEvents = _underflowEvents; droppedSamples = _droppedSamples; lostPackets = _lostPackets; _underflowEvents = 0; _droppedSamples = 0; _lostPackets = 0; } _nextBufferLog = Time.time + 10f; if (underflowEvents > 0) { VOIPPlugin.Log.LogWarning((object)("Voice jitter buffer underflow for " + SpeakerId + " (" + underflowEvents + " silent samples in the last window).")); } if (droppedSamples > 0) { VOIPPlugin.Log.LogWarning((object)("Voice jitter buffer dropped " + droppedSamples + " old samples for " + SpeakerId + " to stay within the max buffer.")); } if (lostPackets > 0) { VOIPPlugin.Log.LogWarning((object)("Voice playback detected " + lostPackets + " missing packet sequence(s) for " + SpeakerId + " in the last window.")); } } } 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 (_bufferedSamples > 0 && _ring != null) { data[i] = _ring[_readIndex]; _readIndex = (_readIndex + 1) % _ring.Length; _bufferedSamples--; } else { data[i] = 0f; _underflowEvents++; } } } } private void OnAudioSetPosition(int position) { } private void EnsureRingCapacity(int capacity) { if (_ring == null || _ring.Length != capacity) { _ring = new float[capacity]; ClearBuffer(); } } private void ClearBuffer() { _readIndex = 0; _writeIndex = 0; _bufferedSamples = 0; } } private const float SpeakerIdleDestroySeconds = 10f; private readonly Dictionary<long, SpeakerPlayback> _speakers = new Dictionary<long, SpeakerPlayback>(); public void Play(VoicePacket packet) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) VoiceMuteState.RememberSpeaker(packet.SpeakerId); if (VoiceMuteState.Deafened || VoiceMuteState.IsMuted(packet.SpeakerId) || packet.OpusPayload == null || packet.OpusPayload.Length == 0 || packet.Samples <= 0) { return; } SpeakerPlayback speaker = GetSpeaker(packet.SpeakerId, packet.SampleRate); speaker.UpdateSource(packet.SpeakerPosition); speaker.TrackSequence(packet.Sequence); try { speaker.Enqueue(speaker.Codec.Decode(packet.OpusPayload, packet.Samples, packet.SampleRate)); VoiceHud.MarkReceiving(); } 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 VoiceRateLimiter { private sealed class Bucket { public float Tokens; public float LastSeen; public Bucket(float tokens, float lastSeen) { Tokens = tokens; LastSeen = lastSeen; } } private const float BurstSeconds = 1.5f; private const float MaxSilenceBeforeResetSeconds = 10f; private readonly Dictionary<long, Bucket> _buckets = new Dictionary<long, Bucket>(); public bool Allow(long senderPeerId) { float time = Time.time; float num = Mathf.Max(0.02f, (float)VoiceRuntimeSettings.FrameMilliseconds / 1000f); float num2 = 1f / num; float num3 = Mathf.Max(3f, num2 * 1.5f); if (!_buckets.TryGetValue(senderPeerId, out var value)) { value = new Bucket(num3, time); _buckets[senderPeerId] = value; } if (time - value.LastSeen > 10f) { value.Tokens = num3; } else { value.Tokens = Mathf.Min(num3, value.Tokens + (time - value.LastSeen) * num2); } value.LastSeen = time; if (value.Tokens < 1f) { return false; } value.Tokens -= 1f; return true; } } internal sealed class VoiceServer : MonoBehaviour { private readonly VoiceRateLimiter _rateLimiter = new VoiceRateLimiter(); private BreakoutModuleContext _context; internal static VoiceServer Instance { get; private set; } private void Awake() { Instance = this; } public void Initialize(BreakoutModuleContext context) { _context = context; } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } public VoicePacket Relay(long senderPeerId, VoicePacket packet) { //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null || !BreakoutSide.IsServer) { return null; } if (!VoiceRuntimeSettings.Enabled) { return null; } if (!_rateLimiter.Allow(senderPeerId)) { VoiceLog.WarningRateLimited("voice-rate-limit-" + senderPeerId, "Dropped voice frames from peer " + senderPeerId + " because they exceeded the configured voice rate.", 5f); return null; } if (!TryGetServerKnownPosition(senderPeerId, out var position)) { VoiceLog.WarningRateLimited("voice-missing-position-" + senderPeerId, "Dropped voice frame from peer " + senderPeerId + " because the server could not resolve its position.", 5f); return null; } VoicePacket voicePacket = packet.WithServerSpeaker(senderPeerId, position); float proximityMeters = VoiceRuntimeSettings.ProximityMeters; float num = proximityMeters * proximityMeters; int num2 = 0; foreach (ZNetPeer connectedPeer in BreakoutPeers.ConnectedPeers) { if (connectedPeer != null && connectedPeer.m_uid != senderPeerId) { Vector3 val = connectedPeer.GetRefPos() - voicePacket.SpeakerPosition; if (!(((Vector3)(ref val)).sqrMagnitude > num) && Server.SendToClient<VoicePacket>(connectedPeer.m_uid, "voip.voice.frame", voicePacket, (_context != null) ? _context.ModGuid : "com.breakoutmods.voip")) { num2++; } } } if (_context != null) { VoicePacketRelayedEvent voicePacketRelayedEvent = new VoicePacketRelayedEvent(voicePacket.SpeakerId, num2, voicePacket.Sequence); _context.Events.Publish<VoicePacketRelayedEvent>(voicePacketRelayedEvent); _context.Events.Publish<VoicePacketRelayedEvent>("voip.voice.relayed", voicePacketRelayedEvent); } return voicePacket; } private static bool TryGetServerKnownPosition(long senderPeerId, out Vector3 position) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_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) if (senderPeerId == ZNet.GetUID() && (Object)(object)Player.m_localPlayer != (Object)null) { position = ((Component)Player.m_localPlayer).transform.position; return true; } foreach (ZNetPeer connectedPeer in ZNet.instance.GetConnectedPeers()) { if (connectedPeer != null && connectedPeer.m_uid == senderPeerId) { position = connectedPeer.GetRefPos(); return true; } } position = Vector3.zero; return false; } } 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]; } } } public sealed class VoiceSettingsAppliedEvent : IBreakoutEvent { public bool Changed { get; private set; } public string Summary { get; private set; } public VoiceSettingsAppliedEvent(bool changed, string summary) { Changed = changed; Summary = summary ?? string.Empty; } } public sealed class VoicePacketRelayedEvent : IBreakoutEvent { public long SpeakerId { get; private set; } public int Recipients { get; private set; } public int Sequence { get; private set; } public VoicePacketRelayedEvent(long speakerId, int recipients, int sequence) { SpeakerId = speakerId; Recipients = recipients; Sequence = sequence; } } 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)) { VOIPPlugin.Log.LogInfo((object)message); } } public static void WarningRateLimited(string key, string message, float intervalSeconds) { if (ShouldLog(key, intervalSeconds)) { VOIPPlugin.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 = "voip.voice.frame"; internal const string SettingsName = "voip.settings"; private static readonly BreakoutRpcRateLimit VoiceFrameRateLimit = BreakoutRpcRateLimit.ForMessagesPerSecond(60f, 3f); private BreakoutModuleContext _context; private VoiceClient _client; private VoiceServer _server; private VoicePlayback _playback; public void Initialize(BreakoutModuleContext context, VoiceClient client, VoiceServer server, VoicePlayback playback) { _context = context; _client = client; _server = server; _playback = playback; Server.Register<VoicePacket>("voip.voice.frame", (BreakoutRpcHandler<VoicePacket>)OnServerVoiceFrame, VoiceFrameRateLimit); Client.Register<VoicePacket>("voip.voice.frame", (BreakoutRpcHandler<VoicePacket>)OnClientVoiceFrame); BreakoutSettingsSync.RegisterServerSettings<VoiceServerSettings>("voip.settings", (Func<VoiceServerSettings>)VoiceRuntimeSettings.CreateServerSettings); Client.Register<VoiceServerSettings>("voip.settings", (Action<VoiceServerSettings>)OnClientSettings); if (_context != null) { _context.Hooks.OnWorldLeft((Action<BreakoutWorldLeftEvent>)OnWorldLeft); _context.Hooks.OnRpcRejected((Action<BreakoutRpcRejectedEvent>)OnRpcRejected); } VOIPPlugin.Log.LogInfo((object)"Voice RPC registered through BreakoutNet."); } public void Send(VoicePacket packet) { if (_client != null) { _client.Send(packet); } } private void OnWorldLeft(BreakoutWorldLeftEvent evt) { if (_client != null) { _client.OnRpcUnavailable(); } } private static void OnRpcRejected(BreakoutRpcRejectedEvent evt) { if (!(evt.RpcName != "voip.voice.frame") || !(evt.RpcName != string.Empty)) { VoiceLog.WarningRateLimited("voice-breakoutnet-rpc-rejected-" + evt.Category, "BreakoutNet rejected a VOIP RPC from peer " + evt.SenderPeerId + ": " + evt.Reason, 10f); } } private void OnServerVoiceFrame(BreakoutRpcContext context, VoicePacket packet) { if (VoiceRuntimeSettings.Enabled) { VoicePacket voicePacket = (((Object)(object)_server != (Object)null) ? _server.Relay(context.SenderPeerId, packet) : null); if (voicePacket != null && (Object)(object)_playback != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null && voicePacket.SpeakerId != ZNet.GetUID()) { _playback.Play(voicePacket); } } } private void OnClientVoiceFrame(BreakoutRpcContext context, VoicePacket packet) { if (!context.IsFromServer) { context.Reject("Voice frame must come from the server."); } else if (!((Object)(object)_playback == (Object)null) && packet.SpeakerId != ZNet.GetUID()) { _playback.Play(packet); } } private void OnClientSettings(VoiceServerSettings settings) { if (_client != null) { _client.ApplyServerSettings(settings); } } } internal sealed class VoicePacket : IBreakoutSerializable { public const int CurrentProtocolVersion = 2; public const int MaxOpusPayloadBytes = 1275; public int ProtocolVersion = 2; public int Sequence; public long SenderPeerId; 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 ZPackage val = new ZPackage(); Write(val); val.SetPos(0); return val; } public static VoicePacket FromPackage(ZPackage package) { VoicePacket voicePacket = new VoicePacket(); voicePacket.Read(package); Validate(voicePacket); return voicePacket; } public void Write(ZPackage package) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) package.Write(ProtocolVersion); package.Write(Sequence); package.Write(SenderPeerId); package.Write(SpeakerId); package.Write(SpeakerPosition); package.Write(SampleRate); package.Write(Samples); package.Write(OpusPayload); } public void Read(ZPackage package) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) ProtocolVersion = package.ReadInt(); Sequence = package.ReadInt(); SenderPeerId = package.ReadLong(); SpeakerId = package.ReadLong(); SpeakerPosition = package.ReadVector3(); SampleRate = package.ReadInt(); Samples = package.ReadInt(); OpusPayload = package.ReadByteArray(); Validate(this); } public static void Validate(VoicePacket packet) { //IL_0137: Unknown result type (might be due to invalid IL or missing references) if (packet == null) { throw new ArgumentNullException("packet"); } if (packet.ProtocolVersion != 2) { throw new InvalidOperationException("Unsupported voice protocol version " + packet.ProtocolVersion + "."); } if (!IsSupportedSampleRate(packet.SampleRate)) { throw new InvalidOperationException("Unsupported voice sample rate " + packet.SampleRate + "."); } if (!IsSupportedSampleCount(packet.SampleRate, packet.Samples)) { throw new InvalidOperationException("Unsupported voice sample count " + packet.Samples + " for sample rate " + packet.SampleRate + "."); } if (packet.OpusPayload == null || packet.OpusPayload.Length == 0) { throw new InvalidOperationException("Voice payload is empty."); } if (packet.OpusPayload.Length > 1275) { throw new InvalidOperationException("Voice payload is too large: " + packet.OpusPayload.Length + " bytes."); } if (!IsFinite(packet.SpeakerPosition)) { throw new InvalidOperationException("Voice speaker position is invalid."); } } public VoicePacket WithServerSpeaker(long senderPeerId, Vector3 serverPosition) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) VoicePacket voicePacket = new VoicePacket(); voicePacket.ProtocolVersion = 2; voicePacket.Sequence = Sequence; voicePacket.SenderPeerId = senderPeerId; voicePacket.SpeakerId = senderPeerId; voicePacket.SpeakerPosition = serverPosition; voicePacket.SampleRate = SampleRate; voicePacket.Samples = Samples; voicePacket.OpusPayload = OpusPayload; VoicePacket voicePacket2 = voicePacket; Validate(voicePacket2); return voicePacket2; } private static bool IsSupportedSampleRate(int sampleRate) { return sampleRate == 8000 || sampleRate == 12000 || sampleRate == 16000 || sampleRate == 24000 || sampleRate == 48000; } private static bool IsSupportedSampleCount(int sampleRate, int samples) { return samples == sampleRate * 20 / 1000 || samples == sampleRate * 40 / 1000 || samples == sampleRate * 60 / 1000; } private static bool IsFinite(Vector3 value) { return IsFinite(value.x) && IsFinite(value.y) && IsFinite(value.z); } private static bool IsFinite(float value) { return !float.IsNaN(value) && !float.IsInfinity(value); } } 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 VoiceServerSettings CreateServerSettings() { VoiceServerSettings voiceServerSettings = new VoiceServerSettings(); voiceServerSettings.Enabled = VoiceSettings.Enabled.Value; voiceServerSettings.ProximityMeters = VoiceSettings.ProximityMeters.Value; voiceServerSettings.FullVolumeMeters = VoiceSettings.FullVolumeMeters.Value; voiceServerSettings.SampleRate = VoiceSettings.EffectiveSampleRate; voiceServerSettings.FrameMilliseconds = VoiceSettings.EffectiveFrameMilliseconds; voiceServerSettings.OpusBitrate = VoiceSettings.EffectiveOpusBitrate; voiceServerSettings.OpusComplexity = VoiceSettings.EffectiveOpusComplexity; return voiceServerSettings; } 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(); CreateServerSettings().Write(val); val.SetPos(0); return val; } public static bool ApplyServerPackage(ZPackage package, out string summary) { VoiceServerSettings voiceServerSettings = new VoiceServerSettings(); voiceServerSettings.Read(package); return ApplyServerSettings(voiceServerSettings, out summary); } public static bool ApplyServerSettings(VoiceServerSettings settings, out string summary) { summary = string.Empty; if (settings.Version != 1) { VoiceLog.WarningRateLimited("voice-settings-version", "Ignored unsupported voice settings package version " + settings.Version + ".", 30f); return false; } _enabled = settings.Enabled; _proximityMeters = Mathf.Max(1f, settings.ProximityMeters); _fullVolumeMeters = Mathf.Clamp(settings.FullVolumeMeters, 0.1f, _proximityMeters); _sampleRate = SanitizeSampleRate(settings.SampleRate); _frameMilliseconds = SanitizeFrameMilliseconds(settings.FrameMilliseconds); _opusBitrate = Mathf.Clamp(settings.OpusBitrate, 6000, 128000); _opusComplexity = Mathf.Clamp(settings.OpusComplexity, 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 sealed class VoiceServerSettings : IBreakoutSerializable { public const int CurrentVersion = 1; public int Version = 1; public bool Enabled; public float ProximityMeters; public float FullVolumeMeters; public int SampleRate; public int FrameMilliseconds; public int OpusBitrate; public int OpusComplexity; public void Write(ZPackage package) { package.Write(Version); package.Write(Enabled); package.Write(ProximityMeters); package.Write(FullVolumeMeters); package.Write(SampleRate); package.Write(FrameMilliseconds); package.Write(OpusBitrate); package.Write(OpusComplexity); } public void Read(ZPackage package) { Version = package.ReadInt(); Enabled = package.ReadBool(); ProximityMeters = package.ReadSingle(); FullVolumeMeters = package.ReadSingle(); SampleRate = package.ReadInt(); FrameMilliseconds = package.ReadInt(); OpusBitrate = package.ReadInt(); OpusComplexity = package.ReadInt(); } } internal static class VoiceSettings { public static ConfigEntry<bool> Enabled { get; private set; } public static ConfigEntry<string> PushToTalkKey { get; private set; } public static ConfigEntry<string> MicrophoneDevice { get; private set; } public static ConfigEntry<int> MicrophoneStopDelayMilliseconds { get; private set; } public static ConfigEntry<string> ToggleDeafenKey { get; private set; } public static ConfigEntry<string> ToggleMuteLastSpeakerKey { get; private set; } public static ConfigEntry<string> MutedSpeakerIds { 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 => ParseKeyCode(PushToTalkKey.Value, (KeyCode)118); public static KeyCode ToggleDeafenKeyCode => ParseKeyCode(ToggleDeafenKey.Value, (KeyCode)98); public static KeyCode ToggleMuteLastSpeakerKeyCode => ParseKeyCode(ToggleMuteLastSpeakerKey.Value, (KeyCode)109); 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 int EffectiveMicrophoneStopDelayMilliseconds => Mathf.Clamp(MicrophoneStopDelayMilliseconds.Value, 0, 5000); 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."); MicrophoneDevice = config.Bind<string>("Input", "MicrophoneDevice", "", "Preferred Unity microphone device name. Leave empty to use the default device."); MicrophoneStopDelayMilliseconds = config.Bind<int>("Input", "MicrophoneStopDelayMilliseconds", 250, "Delay before stopping the microphone after push-to-talk is released."); ToggleDeafenKey = config.Bind<string>("Input", "ToggleDeafenKey", "B", "Unity KeyCode name used to toggle local deafen."); ToggleMuteLastSpeakerKey = config.Bind<string>("Input", "ToggleMuteLastSpeakerKey", "M", "Unity KeyCode name used to mute or unmute the last received speaker."); MutedSpeakerIds = config.Bind<string>("Moderation", "MutedSpeakerIds", "", "Comma-separated VOIP speaker IDs muted locally."); 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."); } private static KeyCode ParseKeyCode(string value, KeyCode fallback) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) KeyCode result; return Enum.TryParse<KeyCode>(value, ignoreCase: true, out result) ? result : fallback; } } internal static class VoiceValidationHarness { public static bool InvalidProtocolVersionFails() { return Fails(CreatePackage(999, 1, 2L, 16000, 960, new byte[1] { 1 })); } public static bool InvalidSampleRateFails() { return Fails(CreatePackage(2, 1, 1L, 11025, 220, new byte[1] { 1 })); } public static bool MismatchedSampleCountFails() { return Fails(CreatePackage(2, 1, 1L, 16000, 123, new byte[1] { 1 })); } public static bool EmptyPayloadFails() { return Fails(CreatePackage(2, 1, 1L, 16000, 960, new byte[0])); } public static bool OversizedPayloadFails() { return Fails(CreatePackage(2, 1, 1L, 16000, 960, new byte[1276])); } private static bool Fails(ZPackage package) { try { VoicePacket.FromPackage(package); return false; } catch { return true; } } private static ZPackage CreatePackage(int protocolVersion, int sequence, long speakerId, int sampleRate, int samples, byte[] payload) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) ZPackage val = new ZPackage(); val.Write(protocolVersion); val.Write(sequence); val.Write(speakerId); val.Write(speakerId); val.Write(Vector3.zero); val.Write(sampleRate); val.Write(samples); val.Write(payload); return val; } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("com.breakoutmods.voip", "VOIP", "0.4.1")] public sealed class VOIPPlugin : BaseUnityPlugin { public const string ModGuid = "com.breakoutmods.voip"; public const string ModName = "VOIP"; public const string ModVersion = "0.4.1"; private BreakoutModApp _breakoutApp; private GameObject _runnerObject; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; VoiceSettings.Bind(((BaseUnityPlugin)this).Config); _breakoutApp = BreakoutNet.ForPlugin((BaseUnityPlugin)(object)this, "com.breakoutmods.voip").Build(); _runnerObject = new GameObject("VOIP"); Object.DontDestroyOnLoad((Object)(object)_runnerObject); VoiceNetwork voiceNetwork = _runnerObject.AddComponent<VoiceNetwork>(); VoiceServer voiceServer = _runnerObject.AddComponent<VoiceServer>(); VoiceClient client = null; VoicePlayback playback = null; voiceServer.Initialize(_breakoutApp.Context); if (!Application.isBatchMode) { client = new VoiceClient(_breakoutApp.Context); playback = _runnerObject.AddComponent<VoicePlayback>(); VoiceCapture voiceCapture = _runnerObject.AddComponent<VoiceCapture>(); voiceCapture.Initialize(voiceNetwork); _runnerObject.AddComponent<VoiceHud>(); } voiceNetwork.Initialize(_breakoutApp.Context, client, voiceServer, playback); ((BaseUnityPlugin)this).Logger.LogInfo((object)"VOIP 0.4.1 loaded"); } private void OnDestroy() { if ((Object)(object)_runnerObject != (Object)null) { Object.Destroy((Object)(object)_runnerObject); } if (_breakoutApp != null) { _breakoutApp.Dispose(); _breakoutApp = null; } } } } 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]; }