using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PEAK_AutoMic.Patches;
using Photon.Pun;
using Photon.Realtime;
using Photon.Voice;
using Photon.Voice.Unity;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PEAK_AutoMic")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.4.0")]
[assembly: AssemblyInformationalVersion("0.1.4+a9dd7c0158b67173e7536647011eedb6081b59e7")]
[assembly: AssemblyProduct("PEAK_AutoMic")]
[assembly: AssemblyTitle("PEAK_AutoMic")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.4.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace BepInEx
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
[Conditional("CodeGeneration")]
internal sealed class BepInAutoPluginAttribute : Attribute
{
public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
{
}
}
}
namespace BepInEx.Preloader.Core.Patching
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
[Conditional("CodeGeneration")]
internal sealed class PatcherAutoPluginAttribute : Attribute
{
public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
{
}
}
}
namespace PEAK_AutoMic
{
public class BiQuadFilter
{
private double a0;
private double a1;
private double a2;
private double a3;
private double a4;
private float x1;
private float x2;
private float y1;
private float y2;
public float Transform(float inSample)
{
double num = a0 * (double)inSample + a1 * (double)x1 + a2 * (double)x2 - a3 * (double)y1 - a4 * (double)y2;
x2 = x1;
x1 = inSample;
y2 = y1;
y1 = (float)num;
return y1;
}
private void SetCoefficients(double aa0, double aa1, double aa2, double b0, double b1, double b2)
{
a0 = b0 / aa0;
a1 = b1 / aa0;
a2 = b2 / aa0;
a3 = aa1 / aa0;
a4 = aa2 / aa0;
}
public void SetLowPassFilter(float sampleRate, float cutoffFrequency, float q)
{
double num = Math.PI * 2.0 * (double)cutoffFrequency / (double)sampleRate;
double num2 = Math.Cos(num);
double num3 = Math.Sin(num) / (double)(2f * q);
double b = (1.0 - num2) / 2.0;
double b2 = 1.0 - num2;
double b3 = (1.0 - num2) / 2.0;
double aa = 1.0 + num3;
double aa2 = -2.0 * num2;
double aa3 = 1.0 - num3;
SetCoefficients(aa, aa2, aa3, b, b2, b3);
}
public void SetPeakingEq(float sampleRate, float centreFrequency, float q, float dbGain)
{
double num = Math.PI * 2.0 * (double)centreFrequency / (double)sampleRate;
double num2 = Math.Cos(num);
double num3 = Math.Sin(num);
double num4 = num3 / (double)(2f * q);
double num5 = Math.Pow(10.0, dbGain / 40f);
double b = 1.0 + num4 * num5;
double b2 = -2.0 * num2;
double b3 = 1.0 - num4 * num5;
double aa = 1.0 + num4 / num5;
double aa2 = -2.0 * num2;
double aa3 = 1.0 - num4 / num5;
SetCoefficients(aa, aa2, aa3, b, b2, b3);
}
public void SetHighPassFilter(float sampleRate, float cutoffFrequency, float q)
{
double num = Math.PI * 2.0 * (double)cutoffFrequency / (double)sampleRate;
double num2 = Math.Cos(num);
double num3 = Math.Sin(num) / (double)(2f * q);
double b = (1.0 + num2) / 2.0;
double b2 = 0.0 - (1.0 + num2);
double b3 = (1.0 + num2) / 2.0;
double aa = 1.0 + num3;
double aa2 = -2.0 * num2;
double aa3 = 1.0 - num3;
SetCoefficients(aa, aa2, aa3, b, b2, b3);
}
public static BiQuadFilter LowPassFilter(float sampleRate, float cutoffFrequency, float q)
{
BiQuadFilter biQuadFilter = new BiQuadFilter();
biQuadFilter.SetLowPassFilter(sampleRate, cutoffFrequency, q);
return biQuadFilter;
}
public static BiQuadFilter HighPassFilter(float sampleRate, float cutoffFrequency, float q)
{
BiQuadFilter biQuadFilter = new BiQuadFilter();
biQuadFilter.SetHighPassFilter(sampleRate, cutoffFrequency, q);
return biQuadFilter;
}
public static BiQuadFilter BandPassFilterConstantSkirtGain(float sampleRate, float centreFrequency, float q)
{
double num = Math.PI * 2.0 * (double)centreFrequency / (double)sampleRate;
double num2 = Math.Cos(num);
double num3 = Math.Sin(num);
double num4 = num3 / (double)(2f * q);
double b = num3 / 2.0;
int num5 = 0;
double b2 = (0.0 - num3) / 2.0;
double num6 = 1.0 + num4;
double num7 = -2.0 * num2;
double num8 = 1.0 - num4;
return new BiQuadFilter(num6, num7, num8, b, num5, b2);
}
public static BiQuadFilter BandPassFilterConstantPeakGain(float sampleRate, float centreFrequency, float q)
{
double num = Math.PI * 2.0 * (double)centreFrequency / (double)sampleRate;
double num2 = Math.Cos(num);
double num3 = Math.Sin(num);
double num4 = num3 / (double)(2f * q);
double b = num4;
int num5 = 0;
double b2 = 0.0 - num4;
double num6 = 1.0 + num4;
double num7 = -2.0 * num2;
double num8 = 1.0 - num4;
return new BiQuadFilter(num6, num7, num8, b, num5, b2);
}
public static BiQuadFilter NotchFilter(float sampleRate, float centreFrequency, float q)
{
double num = Math.PI * 2.0 * (double)centreFrequency / (double)sampleRate;
double num2 = Math.Cos(num);
double num3 = Math.Sin(num);
double num4 = num3 / (double)(2f * q);
int num5 = 1;
double b = -2.0 * num2;
int num6 = 1;
double num7 = 1.0 + num4;
double num8 = -2.0 * num2;
double num9 = 1.0 - num4;
return new BiQuadFilter(num7, num8, num9, num5, b, num6);
}
public static BiQuadFilter AllPassFilter(float sampleRate, float centreFrequency, float q)
{
double num = Math.PI * 2.0 * (double)centreFrequency / (double)sampleRate;
double num2 = Math.Cos(num);
double num3 = Math.Sin(num);
double num4 = num3 / (double)(2f * q);
double b = 1.0 - num4;
double b2 = -2.0 * num2;
double b3 = 1.0 + num4;
double num5 = 1.0 + num4;
double num6 = -2.0 * num2;
double num7 = 1.0 - num4;
return new BiQuadFilter(num5, num6, num7, b, b2, b3);
}
public static BiQuadFilter PeakingEQ(float sampleRate, float centreFrequency, float q, float dbGain)
{
BiQuadFilter biQuadFilter = new BiQuadFilter();
biQuadFilter.SetPeakingEq(sampleRate, centreFrequency, q, dbGain);
return biQuadFilter;
}
public static BiQuadFilter LowShelf(float sampleRate, float cutoffFrequency, float shelfSlope, float dbGain)
{
double num = Math.PI * 2.0 * (double)cutoffFrequency / (double)sampleRate;
double num2 = Math.Cos(num);
double num3 = Math.Sin(num);
double num4 = Math.Pow(10.0, dbGain / 40f);
double num5 = num3 / 2.0 * Math.Sqrt((num4 + 1.0 / num4) * (double)(1f / shelfSlope - 1f) + 2.0);
double num6 = 2.0 * Math.Sqrt(num4) * num5;
double b = num4 * (num4 + 1.0 - (num4 - 1.0) * num2 + num6);
double b2 = 2.0 * num4 * (num4 - 1.0 - (num4 + 1.0) * num2);
double b3 = num4 * (num4 + 1.0 - (num4 - 1.0) * num2 - num6);
double num7 = num4 + 1.0 + (num4 - 1.0) * num2 + num6;
double num8 = -2.0 * (num4 - 1.0 + (num4 + 1.0) * num2);
double num9 = num4 + 1.0 + (num4 - 1.0) * num2 - num6;
return new BiQuadFilter(num7, num8, num9, b, b2, b3);
}
public static BiQuadFilter HighShelf(float sampleRate, float cutoffFrequency, float shelfSlope, float dbGain)
{
double num = Math.PI * 2.0 * (double)cutoffFrequency / (double)sampleRate;
double num2 = Math.Cos(num);
double num3 = Math.Sin(num);
double num4 = Math.Pow(10.0, dbGain / 40f);
double num5 = num3 / 2.0 * Math.Sqrt((num4 + 1.0 / num4) * (double)(1f / shelfSlope - 1f) + 2.0);
double num6 = 2.0 * Math.Sqrt(num4) * num5;
double b = num4 * (num4 + 1.0 + (num4 - 1.0) * num2 + num6);
double b2 = -2.0 * num4 * (num4 - 1.0 + (num4 + 1.0) * num2);
double b3 = num4 * (num4 + 1.0 + (num4 - 1.0) * num2 - num6);
double num7 = num4 + 1.0 - (num4 - 1.0) * num2 + num6;
double num8 = 2.0 * (num4 - 1.0 - (num4 + 1.0) * num2);
double num9 = num4 + 1.0 - (num4 - 1.0) * num2 - num6;
return new BiQuadFilter(num7, num8, num9, b, b2, b3);
}
private BiQuadFilter()
{
x1 = (x2 = 0f);
y1 = (y2 = 0f);
}
private BiQuadFilter(double a0, double a1, double a2, double b0, double b1, double b2)
{
SetCoefficients(a0, a1, a2, b0, b1, b2);
x1 = (x2 = 0f);
y1 = (y2 = 0f);
}
}
internal class PlayerVoiceInfo
{
private float outputLevel;
private readonly int processBuffer;
private bool initialGate;
private float MinLUFS;
public readonly int voiceID;
private BiQuadFilter preFilter;
private BiQuadFilter rlbFilter;
private const int TERM_MS = 800;
private const float TARGET_LUFS = -27f;
private const float MAX_DYNAMIC_RANGE = 6.5f;
private const float INITIAL_LUFS_GATE = -47f;
private const float NOISE_GATE = 4f;
private const float MAX_DECAY = 0.04f;
private const float LUFS_CEILING = -15f;
private float[] squaredBuffer;
private int bufferIndex;
private float runningSum;
private int sampleCount;
private int falloffCount;
public float MaxLUFS { get; set; }
public PlayerVoiceInfo(int samplingRate, int voiceId = -1)
{
preFilter = BiQuadFilter.HighShelf(samplingRate, 1500f, 0.707f, 4f);
rlbFilter = BiQuadFilter.HighPassFilter(samplingRate, 100f, 0.707f);
MaxLUFS = -300f;
MinLUFS = -20.5f;
outputLevel = 1f;
voiceID = voiceId;
processBuffer = 800 * samplingRate / 1000;
squaredBuffer = new float[processBuffer];
initialGate = false;
}
public void ProcessSamples(float[] samples)
{
foreach (float inSample in samples)
{
float inSample2 = preFilter.Transform(inSample);
float num = rlbFilter.Transform(inSample2);
float num2 = num * num;
if (sampleCount >= processBuffer)
{
runningSum -= squaredBuffer[bufferIndex];
}
squaredBuffer[bufferIndex] = num2;
runningSum += num2;
bufferIndex = (bufferIndex + 1) % processBuffer;
if (sampleCount < processBuffer)
{
sampleCount++;
}
}
falloffCount += samples.Length;
}
public float GetShortTermLUFS()
{
if (sampleCount < processBuffer)
{
return -300f;
}
double num = runningSum / (float)processBuffer;
if (num <= 0.0)
{
return -300f;
}
return (float)(10.0 * Math.Log10(num) - 0.691);
}
public void RecordLUFS(float level)
{
if (sampleCount < processBuffer)
{
return;
}
if (falloffCount > processBuffer)
{
if (MaxLUFS > -27f)
{
MaxLUFS -= 0.04f;
}
falloffCount -= processBuffer;
}
MaxLUFS = Math.Max(level, MaxLUFS);
MinLUFS = Math.Min(level, MinLUFS);
if (!initialGate)
{
if (!(MaxLUFS > -47f))
{
return;
}
initialGate = true;
}
float num = Math.Max(MaxLUFS - 6.5f, level);
double num2 = Math.Min((level - MinLUFS) / 4f, 1.0);
double num3 = Math.Sin(num2 * Math.PI * 0.5);
num3 = num3 * num3 * num3 * num3;
outputLevel = (float)Math.Pow(10.0, (double)(-27f - num) / 20.0) * (float)num3;
}
public float GetOutputLevel()
{
return outputLevel;
}
}
[BepInPlugin("PEAK_AutoMic", "PEAK_AutoMic", "0.1.4")]
public class Plugin : BaseUnityPlugin
{
internal static Harmony Harmony = null;
internal static AudioLevels? LevelsReference = null;
internal static bool _patched = false;
public const string Id = "PEAK_AutoMic";
internal static ManualLogSource Log { get; private set; } = null;
internal static ConcurrentDictionary<string, PlayerVoiceInfo> PlayerVoices { get; private set; } = new ConcurrentDictionary<string, PlayerVoiceInfo>();
public static string Name => "PEAK_AutoMic";
public static string Version => "0.1.4";
private void Awake()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Harmony = new Harmony("PEAK_AutoMic");
Harmony.PatchAll(typeof(RemoteVoiceLinkPatches));
Log.LogInfo((object)("Plugin " + Name + " is loaded!"));
}
}
}
namespace PEAK_AutoMic.Patches
{
internal class RemoteVoiceLinkPatches
{
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
public static void Postfix(VoiceConnection __instance)
{
if ((Object)(object)__instance != (Object)null)
{
Plugin.Log.LogInfo((object)("Found VoiceConnection instance: " + ((Object)__instance).name));
__instance.RemoteVoiceAdded += __instance_RemoteVoiceAdded;
}
else
{
Plugin.Log.LogError((object)"VoiceConnection constructor returned NULL????????");
}
}
private static void __instance_RemoteVoiceAdded(RemoteVoiceLink link)
{
RemoteVoiceLink link2 = link;
if (link2 == null)
{
Plugin.Log.LogError((object)"RemoteVoiceLink was NULL????????");
return;
}
Plugin.Log.LogInfo((object)$"Found RemoteVoiceLink for player #{link2.PlayerId}");
lock (PhotonNetwork.PlayerList)
{
Player[] playerList = PhotonNetwork.PlayerList;
if (playerList != null)
{
for (int i = 0; i < playerList.Length; i++)
{
if (playerList[i] != null && playerList[i].ActorNumber == link2.PlayerId)
{
string userId = playerList[i].UserId;
if (userId != null)
{
Plugin.PlayerVoices.TryRemove(userId, out PlayerVoiceInfo _);
}
}
}
}
}
link2.FloatFrameDecoded += delegate(FrameOut<float> frame)
{
string text = null;
lock (PhotonNetwork.PlayerList)
{
Player[] playerList2 = PhotonNetwork.PlayerList;
if (playerList2 != null)
{
for (int j = 0; j < playerList2.Length; j++)
{
if (playerList2[j] != null && playerList2[j].ActorNumber == link2.PlayerId)
{
text = playerList2[j].UserId;
if (text != null)
{
break;
}
}
}
}
}
if (text != null && frame != null && frame.Buf != null)
{
if (!Plugin.PlayerVoices.TryGetValue(text, out PlayerVoiceInfo value2))
{
value2 = new PlayerVoiceInfo(((VoiceInfo)(ref link2.VoiceInfo)).SamplingRate, link2.VoiceId);
Plugin.PlayerVoices.TryAdd(text, value2);
}
value2.ProcessSamples(frame.Buf);
float shortTermLUFS = value2.GetShortTermLUFS();
value2.RecordLUFS(shortTermLUFS);
float num = value2.GetOutputLevel() * 0.5f;
float playerLevel = AudioLevels.GetPlayerLevel(text);
if (Math.Abs(num - playerLevel) > 0.01f)
{
AudioLevels.SetPlayerLevel(text, Math.Clamp(num, 0f, 2f));
if ((Object)(object)Plugin.LevelsReference != (Object)null)
{
lock (Plugin.LevelsReference)
{
Plugin.LevelsReference._dirty = true;
}
}
}
}
};
}
[HarmonyPatch(typeof(AudioLevels), "InitNavigation")]
[HarmonyPostfix]
private static void Postfix(AudioLevels __instance)
{
if (Object.op_Implicit((Object)(object)__instance.mainPage))
{
Plugin.LevelsReference = __instance;
}
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}