using System; using ADOFAIRenderer.Core; using ADOFAIRenderer.Util; using ADOFAIRenderer.Util.Audio; using HarmonyLib; using UnityEngine; using UnityEngine.Audio; namespace ADOFAIRenderer.Patch.Engine { [HarmonyPatch(typeof(AudioManager), "_Play")] public static class AudioManagerPlayPatch { [HarmonyPrefix] public static bool Prefix(string snd, double time, AudioMixerGroup group, float volume, int priority) { if (RenderManager.IsCapturingActive && RenderManager.Instance.Configuration.RenderAudio) { // Cache the clip on the main thread AudioClipCache.GetOrCache(snd, RenderManager.Instance.Configuration.AudioChannels, RenderManager.Instance.Configuration.AudioSampleRate, allowLoad: true); } return true; // Let the original method execute to prevent NullReferenceException } [HarmonyPostfix] public static void Postfix(AudioSource __result, string snd, double time, AudioMixerGroup group, float volume, int priority) { if (RenderManager.IsCapturingActive && RenderManager.Instance.Configuration.RenderAudio && __result != null) { // Convert absolute DSP time to relative time in seconds from render start double relativeStartTime = time - RenderManager.Instance.dspTimeBase; // Register event to the offline mixer (default pitch = 1.0f) and map it to the AudioSource OfflineAudioMixer.RegisterSoundEvent(__result, snd, relativeStartTime, -1.0, volume, 1.0f); } } } [HarmonyPatch(typeof(scrConductor), "PlayWithEndTime")] public static class PlayWithEndTimePatch { [HarmonyPrefix] public static bool Prefix(string snd, double time, double endTime, float volume, int priority) { if (RenderManager.IsCapturingActive && RenderManager.Instance.Configuration.RenderAudio) { // Cache the clip on the main thread AudioClipCache.GetOrCache(snd, RenderManager.Instance.Configuration.AudioChannels, RenderManager.Instance.Configuration.AudioSampleRate, allowLoad: true); // Convert absolute DSP times to relative times in seconds from render start double relativeStartTime = time - RenderManager.Instance.dspTimeBase; double relativeEndTime = endTime - RenderManager.Instance.dspTimeBase; // Register looping sound event to the offline mixer (default pitch = 1.0f) OfflineAudioMixer.RegisterSoundEvent(snd, relativeStartTime, relativeEndTime, volume, 1.0f); } return true; // Let the original method execute } } [HarmonyPatch(typeof(AudioSource), "pitch", MethodType.Setter)] public static class AudioSourcePitchPatch { [HarmonyPostfix] public static void Postfix(AudioSource __instance, float value) { if (RenderManager.IsCapturingActive && RenderManager.Instance.Configuration.RenderAudio) { if (OfflineAudioMixer.TryGetSoundEvent(__instance, out var soundEvent)) { soundEvent.Pitch = value; } } } } [HarmonyPatch(typeof(AudioSource), "SetScheduledEndTime", typeof(double))] public static class AudioSourceSetScheduledEndTimePatch { [HarmonyPostfix] public static void Postfix(AudioSource __instance, double time) { if (RenderManager.IsCapturingActive && RenderManager.Instance.Configuration.RenderAudio) { if (OfflineAudioMixer.TryGetSoundEvent(__instance, out var soundEvent)) { soundEvent.EndTime = time - RenderManager.Instance.dspTimeBase; } } } } [HarmonyPatch(typeof(AudioSource), "Stop", new Type[0])] public static class AudioSourceStopPatch { [HarmonyPostfix] public static void Postfix(AudioSource __instance) { if (RenderManager.IsCapturingActive && RenderManager.Instance.Configuration.RenderAudio) { OfflineAudioMixer.RemoveSourceMapping(__instance); } } } }