SHA256
Deactivate Mapped Effect Sources During Render
This commit is contained in:
2 files changed
+45
-4
No files matched your search
@@ -9,6 +9,7 @@ using System.Linq;
|
|||||||
using ADOFAIRenderer.API;
|
using ADOFAIRenderer.API;
|
||||||
using ADOFAIRenderer.Core.Data;
|
using ADOFAIRenderer.Core.Data;
|
||||||
using ADOFAIRenderer.Data;
|
using ADOFAIRenderer.Data;
|
||||||
|
using ADOFAIRenderer.Patch.Engine;
|
||||||
using ADOFAIRenderer.UI;
|
using ADOFAIRenderer.UI;
|
||||||
using ADOFAIRenderer.UI.Window;
|
using ADOFAIRenderer.UI.Window;
|
||||||
using ADOFAIRenderer.Util;
|
using ADOFAIRenderer.Util;
|
||||||
@@ -424,6 +425,7 @@ internal class RenderManager : MonoBehaviour
|
|||||||
{
|
{
|
||||||
AudioMixer.UpdateBGM(AudioTime, dspTimeBase);
|
AudioMixer.UpdateBGM(AudioTime, dspTimeBase);
|
||||||
AudioMixer.Commit((frameCount + 1) / Configuration.RenderFPS);
|
AudioMixer.Commit((frameCount + 1) / Configuration.RenderFPS);
|
||||||
|
EffectSource.DeactivateMappedSources(AudioMixer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!texture) return;
|
if (!texture) return;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using ADOFAIRenderer.Core;
|
using ADOFAIRenderer.Core;
|
||||||
using ADOFAIRenderer.Util.Audio;
|
using ADOFAIRenderer.Util.Audio;
|
||||||
using ADOFAIRenderer.Util.Audio.Clip;
|
using ADOFAIRenderer.Util.Audio.Clip;
|
||||||
@@ -51,7 +52,10 @@ public static class AudioManagerPlayPatch
|
|||||||
double relativeStartTime = time - RenderManager.Instance.dspTimeBase;
|
double relativeStartTime = time - RenderManager.Instance.dspTimeBase;
|
||||||
|
|
||||||
// Register event to the offline mixer (default pitch = 1.0f) and map it to the AudioSource
|
// Register event to the offline mixer (default pitch = 1.0f) and map it to the AudioSource
|
||||||
RenderManager.Instance.AudioMixer?.RegisterSoundEvent(__result, snd, relativeStartTime, -1.0, volume, 1.0f, RenderManager.Instance.AudioTime);
|
var mixer = RenderManager.Instance.AudioMixer;
|
||||||
|
if (mixer == null) return;
|
||||||
|
mixer.RegisterSoundEvent(__result, snd, relativeStartTime, -1.0, volume, 1.0f, RenderManager.Instance.AudioTime);
|
||||||
|
EffectSource.DeactivateAtFrameEnd(__result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,18 +107,53 @@ public static class AudioManagerMakeSourcePatch
|
|||||||
var state = PlayWithEndTimePatch.PendingState;
|
var state = PlayWithEndTimePatch.PendingState;
|
||||||
if (state == null || !__result) return;
|
if (state == null || !__result) return;
|
||||||
PlayWithEndTimePatch.PendingState = null;
|
PlayWithEndTimePatch.PendingState = null;
|
||||||
RenderManager.Instance.AudioMixer?.MapSource(__result, state);
|
var mixer = RenderManager.Instance.AudioMixer;
|
||||||
|
if (mixer == null) return;
|
||||||
|
mixer.MapSource(__result, state);
|
||||||
|
EffectSource.DeactivateAtFrameEnd(__result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// AudioSource members of an effect source mapped to a <see cref="SourceState"/> during rendering: the patches below skip the
|
/// AudioSource members of an effect source mapped to a <see cref="SourceState"/> during rendering: the patches below skip the
|
||||||
/// Unity implementation and read or change the state instead (isPlaying, time, timeSamples, pitch, SetScheduledEndTime, Stop).
|
/// Unity implementation and read or change the state instead (isPlaying, time, timeSamples, pitch, SetScheduledEndTime, Stop).
|
||||||
/// Sources without a mapping (the song, menu sounds) use the Unity implementation.
|
/// The patches apply only while <see cref="TryGet"/> returns true: rendering is capturing (RenderManager.IsCapturingActive,
|
||||||
|
/// stage Render), the render has an audio mixer (created when the render starts, cleared when it ends), and the source is mapped
|
||||||
|
/// in that mixer (mappings are created only when RenderAudio is on). Otherwise they run the Unity implementation, so sources
|
||||||
|
/// without a mapping (the song, menu sounds) and all sources outside rendering behave as in the game.
|
||||||
|
///
|
||||||
|
/// The game object of a mapped source is deactivated at the end of the frame it was mapped in: the mixer produces its sound and the
|
||||||
|
/// state answers every member above, so Unity does not process the source. The game activates it again when AudioManager.MakeSource
|
||||||
|
/// reuses it. Active AudioSources add main-thread time per frame in proportion to their count, and dense levels keep thousands of
|
||||||
|
/// scheduled effect sources alive.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class EffectSource
|
internal static class EffectSource
|
||||||
{
|
{
|
||||||
/// <summary>State mapped to <paramref name="source"/> while capturing, with the current render time in <paramref name="now"/>.</summary>
|
/// <summary>Sources mapped during the current frame, deactivated by <see cref="DeactivateMappedSources"/>. Main thread only.</summary>
|
||||||
|
private static readonly List<AudioSource> PendingDeactivation = new();
|
||||||
|
|
||||||
|
/// <summary>Deactivates the game object of <paramref name="source"/> at the end of the current frame (<see cref="DeactivateMappedSources"/>).</summary>
|
||||||
|
public static void DeactivateAtFrameEnd(AudioSource source) => PendingDeactivation.Add(source);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deactivates the game objects of the sources mapped this frame that are still mapped and not destroyed.
|
||||||
|
/// Called by RenderManager.OnPostFrame after the audio commands of the frame are committed, which runs only in stage Render with
|
||||||
|
/// an audio mixer; sources are added only by the render-time registrations (AudioManager._Play and scrConductor.PlayWithEndTime
|
||||||
|
/// patches with RenderAudio on).
|
||||||
|
/// </summary>
|
||||||
|
public static void DeactivateMappedSources(OfflineAudioMixer mixer)
|
||||||
|
{
|
||||||
|
foreach (var source in PendingDeactivation)
|
||||||
|
{
|
||||||
|
if (source && mixer.TryGetSourceState(source, out _)) source.gameObject.SetActive(false);
|
||||||
|
}
|
||||||
|
PendingDeactivation.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// State mapped to <paramref name="source"/> in the mixer of the current render, with the current render time in <paramref name="now"/>.
|
||||||
|
/// False outside rendering (stage below Render), without a mixer, or for a source that is not mapped.
|
||||||
|
/// </summary>
|
||||||
public static bool TryGet(AudioSource source, out SourceState state, out double now)
|
public static bool TryGet(AudioSource source, out SourceState state, out double now)
|
||||||
{
|
{
|
||||||
state = null!;
|
state = null!;
|
||||||
|
|||||||
Reference in new issue
Block a user