From a6733854dea8879f333a740f5b36ab76c0d5fe7d Mon Sep 17 00:00:00 2001 From: Oliver Wong Date: Fri, 20 Mar 2026 18:48:11 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=AF=E8=83=BD=E7=9A=84=E6=80=A7=E8=83=BD?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HandWritten/AmbienceChannelPlayer.cs | 11 +-- .../OCES/Audio/HandWritten/AudioScheduler.cs | 70 ++++++++++++------- .../OCES/Audio/HandWritten/ChannelFader.cs | 26 +++---- .../HandWrittenDefinitions.cs} | 27 +++++++ .../HandWrittenDefinitions.cs.meta} | 0 .../Audio/HandWritten/MusicChannelPlayer.cs | 8 +-- .../Audio/HandWritten/MusicStateRouter.cs | 15 ---- 7 files changed, 90 insertions(+), 67 deletions(-) rename Assets/Scripts/OCES/Audio/{Generated/AudioDefinitions.cs => HandWritten/HandWrittenDefinitions.cs} (52%) rename Assets/Scripts/OCES/Audio/{Generated/AudioDefinitions.cs.meta => HandWritten/HandWrittenDefinitions.cs.meta} (100%) diff --git a/Assets/Scripts/OCES/Audio/HandWritten/AmbienceChannelPlayer.cs b/Assets/Scripts/OCES/Audio/HandWritten/AmbienceChannelPlayer.cs index 67ba749..d290964 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/AmbienceChannelPlayer.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/AmbienceChannelPlayer.cs @@ -62,19 +62,12 @@ namespace OCES.Audio { ContainerPlayHandle outgoing = this.m_fader.CurrentHandle; float outgoingVolume = this.m_fader.CurrentVolume; - float fadeOutOffSet = transition?.FadeOutOffset ?? 0f; - float fadeOutTime = transition?.FadeOutTime ?? 0f; - float fadeInOffSet = transition?.FadeInOffset ?? 0f; - float fadeInTime = transition?.FadeInTime ?? 0f; - - // ContainerPlayHandle outgoingHandle = this.m_currentHandle; - // float outgoingVolume = this.m_currentVolume; this.m_coroutineHost.StartCoroutine( - this.m_fader.FadeOutBranch(outgoing, outgoingVolume,fadeOutOffSet, fadeOutTime)); + this.m_fader.FadeOutBranch(outgoing, outgoingVolume, transition)); yield return this.m_coroutineHost.StartCoroutine( - this.m_fader.FadeInBranch(newContainerId, fadeInOffSet, fadeInTime)); + this.m_fader.FadeInBranch(newContainerId, transition)); } // ───────────────────────────────────────────── diff --git a/Assets/Scripts/OCES/Audio/HandWritten/AudioScheduler.cs b/Assets/Scripts/OCES/Audio/HandWritten/AudioScheduler.cs index 06363fb..757d617 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/AudioScheduler.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/AudioScheduler.cs @@ -18,11 +18,15 @@ namespace OCES.Audio readonly Dictionary m_clipConcurrentCount = new(); readonly List m_activeSounds = new(); + // 复用列表,避免 TryPlay 每帧分配临时 List(原 LINQ .Where().ToList()) + readonly List m_tempSameObject = new(); + readonly List m_tempSameGroup = new(); + readonly List m_tempLowerPriority = new(); + AudioGroupConfig m_groupConfig; AudioMixerGroup m_sfxGroup; AudioMixerGroup m_musicGroup; AudioMixerGroup m_voiceGroup; - AudioMixerGroup m_ambienceGroup; AudioSourcePool m_pool; AudioContainerSelector m_containerSelector; PitchStepManager m_pitchStepManager; @@ -60,8 +64,6 @@ namespace OCES.Audio AudioMixerGroup[] sfx = Find("Master/SFX"); if (sfx.Length > 0) this.m_sfxGroup = sfx[0]; - AudioMixerGroup[] ambience = Find("Master/SFX/Ambience"); - if (ambience.Length > 0) this.m_ambienceGroup = ambience[0]; AudioMixerGroup[] voice = Find("Master/Voice"); if (voice.Length > 0) this.m_voiceGroup = voice[0]; return; @@ -87,15 +89,20 @@ namespace OCES.Audio // 第二层:单 AudioObject/Clip 并发控制 if (audioObject.ThrottleCount != 0) - { // TODO 这里和下面的组控制,每次都会分配新List,可以考虑做成成员变量,每次用完clear - // TODO Linq表达式好用但是GC性能差。如果性能有问题可以考虑换成普通表达 - List sameObject = this.m_activeSounds - .Where(a => a.AudioObject.Id == audioObject.Id) - .ToList(); + { + this.m_tempSameObject.Clear(); + foreach (ActiveSound activeSound in this.m_activeSounds) + { + if (activeSound.AudioObject.Id == audioObject.Id) + { + this.m_tempSameObject.Add(activeSound); + } + } - if (sameObject.Count >= audioObject.ThrottleCount && - !TryKill(sameObject, audioObject.KillMode, $"[Object] {audioObject.Name[0]}")) + if (this.m_tempSameObject.Count >= audioObject.ThrottleCount && + !TryKill(this.m_tempSameObject, audioObject.KillMode, $"[Object] {audioObject.Name[0]}")) return; + } // 第三层:Group 并发控制 @@ -105,18 +112,28 @@ namespace OCES.Audio groupConfig = this.m_groupConfig.QueryById(1); Debug.Log($"未找到{audioObject.Id}对应的组文件,已使用默认配置组1。"); } - List sameGroup = this.m_activeSounds - .Where(a => a.AudioObject.Group == audioObject.Group) - .ToList(); - - if (sameGroup.Count >= groupConfig.GroupThrottleCount) + this.m_tempSameGroup.Clear(); + foreach (ActiveSound activeSound in this.m_activeSounds) { - List lowerPriority = sameGroup - .Where(a => a.AudioObject.Priority > audioObject.Priority) - .ToList(); + if (activeSound.AudioObject.Group == audioObject.Group) + { + this.m_tempSameGroup.Add(activeSound); + } + } + + if (this.m_tempSameGroup.Count >= groupConfig.GroupThrottleCount) + { + this.m_tempLowerPriority.Clear(); + foreach (ActiveSound activeSound in this.m_tempSameGroup) + { + if (activeSound.AudioObject.Priority > audioObject.Priority) + { + this.m_tempLowerPriority.Add(activeSound); + } + } - List killCandidates = lowerPriority.Count > 0 ? lowerPriority : sameGroup; - KillMode killMode = lowerPriority.Count > 0 ? groupConfig.KillMode : audioObject.KillMode; + List killCandidates = this.m_tempLowerPriority.Count > 0 ? this.m_tempLowerPriority : this.m_tempSameGroup; + KillMode killMode = this.m_tempLowerPriority.Count > 0 ? groupConfig.KillMode : audioObject.KillMode; if (!TryKill(killCandidates, killMode, $"[Group] {audioObject.Name[0]}")) return; @@ -125,11 +142,16 @@ namespace OCES.Audio // 第四层:全局并发控制 if (this.m_activeSounds.Count >= k_maxGlobalConcurrent) { - List lowerPriority = this.m_activeSounds - .Where(a => a.AudioObject.Priority > audioObject.Priority) - .ToList(); + this.m_tempLowerPriority.Clear(); + foreach (ActiveSound activeSound in this.m_activeSounds) + { + if (activeSound.AudioObject.Priority > audioObject.Priority) + { + this.m_tempLowerPriority.Add(activeSound); + } + } - if (lowerPriority.Count == 0 || !TryKill(lowerPriority, KillMode.Oldest, "[Global]")) + if (this.m_tempLowerPriority.Count == 0 || !TryKill(this.m_tempLowerPriority, KillMode.Oldest, "[Global]")) return; } diff --git a/Assets/Scripts/OCES/Audio/HandWritten/ChannelFader.cs b/Assets/Scripts/OCES/Audio/HandWritten/ChannelFader.cs index 9a3abfe..b72398f 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/ChannelFader.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/ChannelFader.cs @@ -46,19 +46,19 @@ namespace OCES.Audio /// /// 淡出分支:fire-and-forget,由调用方 StartCoroutine /// - internal IEnumerator FadeOutBranch(ContainerPlayHandle outgoingHandle, float outgoingVolume, float fadeOutOffset, float fadeOutTime) + internal IEnumerator FadeOutBranch(ContainerPlayHandle outgoingHandle, float outgoingVolume, ITransitionConfig transition) { if (outgoingHandle == null) yield break; - if (fadeOutOffset > 0f) + if (transition?.FadeOutOffset > 0f) { - Debug.Log($"Waiting for {fadeOutOffset} to fade out."); - yield return new WaitForSeconds(fadeOutOffset); + Debug.Log($"Waiting for {transition.FadeOutOffset} to fade out."); + yield return new WaitForSeconds(transition.FadeOutOffset); } - if (fadeOutTime > 0f ) + if (transition?.FadeOutTime > 0f ) yield return this.m_coroutineHost.StartCoroutine( - FadeOut(outgoingHandle, outgoingVolume, fadeOutTime)); + FadeOut(outgoingHandle, outgoingVolume, transition.FadeOutTime)); else StopHandle(outgoingHandle); } @@ -67,12 +67,12 @@ namespace OCES.Audio /// 淡入分支:等待 FadeInOffset 后启动新音乐并淡入。 /// 主协程 yield return 此分支,以便 DoTransition 在新音乐就绪后才结束。 /// - internal IEnumerator FadeInBranch(uint newContainerId, float fadeInOffset, float fadeInTime, Action onContainerStarted = null) + internal IEnumerator FadeInBranch(uint newContainerId, ITransitionConfig transition, Action onContainerStarted = null) { - if (fadeInOffset > 0f) + if (transition?.FadeOutOffset > 0f) { - Debug.Log($"Waiting {fadeInOffset} to fade in."); - yield return new WaitForSeconds(fadeInOffset); + Debug.Log($"Waiting {transition.FadeInOffset} to fade in."); + yield return new WaitForSeconds(transition.FadeInOffset); } if (newContainerId == 0) @@ -82,13 +82,13 @@ namespace OCES.Audio yield break; } - float startVolume = fadeInTime > 0f ? 0f : 1f; + float startVolume = transition?.FadeOutOffset > 0f ? 0f : 1f; StartNew(newContainerId, startVolume); - if (fadeInTime > 0f ) + if (transition?.FadeOutOffset > 0f) { yield return this.m_coroutineHost.StartCoroutine( - FadeIn(CurrentHandle, fadeInTime)); + FadeIn(CurrentHandle, transition.FadeInTime)); } } diff --git a/Assets/Scripts/OCES/Audio/Generated/AudioDefinitions.cs b/Assets/Scripts/OCES/Audio/HandWritten/HandWrittenDefinitions.cs similarity index 52% rename from Assets/Scripts/OCES/Audio/Generated/AudioDefinitions.cs rename to Assets/Scripts/OCES/Audio/HandWritten/HandWrittenDefinitions.cs index be17af5..8a8dbbb 100644 --- a/Assets/Scripts/OCES/Audio/Generated/AudioDefinitions.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/HandWrittenDefinitions.cs @@ -62,4 +62,31 @@ namespace OCES.Audio void DeSerialize(BinaryReader reader); void Serialize(BinaryWriter writer); } + + // ───────────────────────────────────────────── + // 辅助接口,让泛型方法同时处理 MusicPath 和 AmbiencePath + // ───────────────────────────────────────────── + + public interface IPathEntry + { + uint Id { get; } + string Path { get; } + uint ContainerId { get; } + int Priority { get; } + } + + public interface ITransitionConfig + { + float FadeOutOffset { get; } + float FadeOutTime { get; } + float FadeInOffset { get; } + float FadeInTime { get; } + } + + public partial class MusicTransition : ITransitionConfig { } + public partial class AmbienceTransition : ITransitionConfig { } + + + public partial class MusicPath : IPathEntry { } + public partial class AmbiencePath : IPathEntry { } } diff --git a/Assets/Scripts/OCES/Audio/Generated/AudioDefinitions.cs.meta b/Assets/Scripts/OCES/Audio/HandWritten/HandWrittenDefinitions.cs.meta similarity index 100% rename from Assets/Scripts/OCES/Audio/Generated/AudioDefinitions.cs.meta rename to Assets/Scripts/OCES/Audio/HandWritten/HandWrittenDefinitions.cs.meta diff --git a/Assets/Scripts/OCES/Audio/HandWritten/MusicChannelPlayer.cs b/Assets/Scripts/OCES/Audio/HandWritten/MusicChannelPlayer.cs index 3ff2906..f7bb44d 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/MusicChannelPlayer.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/MusicChannelPlayer.cs @@ -89,16 +89,12 @@ namespace OCES.Audio // ── 2 & 3. 淡出与淡入并行:两条分支从同一时刻起算各自的 Offset,互不等待 ── ContainerPlayHandle outgoing = this.m_fader.CurrentHandle; float outVol = this.m_fader.CurrentVolume; - float fadeOutOffset = transition?.FadeOutOffset ?? 0f; - float fadeOutTime = transition?.FadeOutTime ?? 0f; - float fadeInOffset = transition?.FadeInOffset ?? 0f; - float fadeInTime = transition?.FadeInTime ?? 0f; this.m_coroutineHost.StartCoroutine( - this.m_fader.FadeOutBranch(outgoing, outVol, fadeOutOffset, fadeOutTime)); + this.m_fader.FadeOutBranch(outgoing, outVol, transition)); yield return this.m_coroutineHost.StartCoroutine( - this.m_fader.FadeInBranch(newContainerId, fadeInOffset, fadeInTime, + this.m_fader.FadeInBranch(newContainerId, transition, onContainerStarted: () => { // Music 独有:记录新 container 和播放起始时间 diff --git a/Assets/Scripts/OCES/Audio/HandWritten/MusicStateRouter.cs b/Assets/Scripts/OCES/Audio/HandWritten/MusicStateRouter.cs index 3b5966c..3585a20 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/MusicStateRouter.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/MusicStateRouter.cs @@ -136,19 +136,4 @@ namespace OCES.Audio return -1; } } - - // ───────────────────────────────────────────── - // 辅助接口,让泛型方法同时处理 MusicPath 和 AmbiencePath - // ───────────────────────────────────────────── - - public interface IPathEntry - { - uint Id { get; } - string Path { get; } - uint ContainerId { get; } - int Priority { get; } - } - - public partial class MusicPath : IPathEntry { } - public partial class AmbiencePath : IPathEntry { } } \ No newline at end of file