From e032f7687fa1035046058acd044961d6f53dffb4 Mon Sep 17 00:00:00 2001 From: Oliver Wong Date: Wed, 25 Mar 2026 17:01:38 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E9=87=8D=E5=A4=8D=E5=88=87?= =?UTF-8?q?=E6=8D=A2State=E7=9A=84=E6=97=B6=E5=80=99=E4=BC=9A=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E9=87=8D=E5=A4=8D=E6=92=AD=E6=94=BE=E5=AF=B9=E5=BA=94?= =?UTF-8?q?Segment=E7=9A=84=E9=97=AE=E9=A2=98=E3=80=82=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8DFadeIn=E8=AF=BB=E5=8F=96=E4=BA=86FadeOut=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E7=9A=84=E9=97=AE=E9=A2=98=E3=80=82=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0Initial=20Delay=E5=8A=9F=E8=83=BD=E3=80=82=20=E9=87=8D?= =?UTF-8?q?=E6=9E=84AudioScheduler.ConfigureSource()=20->=20SetupSource(),?= =?UTF-8?q?=20RegisterActiveSound(),=20StartPlayBack()=E3=80=82=20?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E9=95=BF=E9=9F=B3=E9=A2=91=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E8=87=B3LongAudio=E6=96=87=E4=BB=B6=E5=A4=B9?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Resources/AudioData/AudioObject.bytes | Bin 7593 -> 7593 bytes Assets/Scenes/SampleScene.unity | 95 +++++++- .../OCES/Audio/HandWritten/AudioScheduler.cs | 213 ++++++++++++------ .../HandWritten/HandWrittenDefinitions.cs | 7 + .../OCES/Audio/HandWritten/LongAudio.meta | 3 + .../{ => LongAudio}/AmbienceChannelPlayer.cs | 23 +- .../AmbienceChannelPlayer.cs.meta | 0 .../{ => LongAudio}/AudioContainerSelector.cs | 0 .../AudioContainerSelector.cs.meta | 0 .../{ => LongAudio}/ChannelFader.cs | 9 +- .../{ => LongAudio}/ChannelFader.cs.meta | 0 .../{ => LongAudio}/MusicChannelPlayer.cs | 26 ++- .../MusicChannelPlayer.cs.meta | 0 .../{ => LongAudio}/MusicContainerPlayer.cs | 1 + .../MusicContainerPlayer.cs.meta | 0 .../{ => LongAudio}/MusicStateRouter.cs | 4 + .../{ => LongAudio}/MusicStateRouter.cs.meta | 0 .../{ => LongAudio}/MusicSystem.cs | 0 .../{ => LongAudio}/MusicSystem.cs.meta | 0 19 files changed, 307 insertions(+), 74 deletions(-) create mode 100644 Assets/Scripts/OCES/Audio/HandWritten/LongAudio.meta rename Assets/Scripts/OCES/Audio/HandWritten/{ => LongAudio}/AmbienceChannelPlayer.cs (80%) rename Assets/Scripts/OCES/Audio/HandWritten/{ => LongAudio}/AmbienceChannelPlayer.cs.meta (100%) rename Assets/Scripts/OCES/Audio/HandWritten/{ => LongAudio}/AudioContainerSelector.cs (100%) rename Assets/Scripts/OCES/Audio/HandWritten/{ => LongAudio}/AudioContainerSelector.cs.meta (100%) rename Assets/Scripts/OCES/Audio/HandWritten/{ => LongAudio}/ChannelFader.cs (96%) rename Assets/Scripts/OCES/Audio/HandWritten/{ => LongAudio}/ChannelFader.cs.meta (100%) rename Assets/Scripts/OCES/Audio/HandWritten/{ => LongAudio}/MusicChannelPlayer.cs (87%) rename Assets/Scripts/OCES/Audio/HandWritten/{ => LongAudio}/MusicChannelPlayer.cs.meta (100%) rename Assets/Scripts/OCES/Audio/HandWritten/{ => LongAudio}/MusicContainerPlayer.cs (99%) rename Assets/Scripts/OCES/Audio/HandWritten/{ => LongAudio}/MusicContainerPlayer.cs.meta (100%) rename Assets/Scripts/OCES/Audio/HandWritten/{ => LongAudio}/MusicStateRouter.cs (98%) rename Assets/Scripts/OCES/Audio/HandWritten/{ => LongAudio}/MusicStateRouter.cs.meta (100%) rename Assets/Scripts/OCES/Audio/HandWritten/{ => LongAudio}/MusicSystem.cs (100%) rename Assets/Scripts/OCES/Audio/HandWritten/{ => LongAudio}/MusicSystem.cs.meta (100%) diff --git a/Assets/Resources/AudioData/AudioObject.bytes b/Assets/Resources/AudioData/AudioObject.bytes index 10feee0bd524b8e528cacdf017544ee88b8c5bb1..900b2eea4bd852319d02c21a9eee6717ee8023cd 100644 GIT binary patch delta 416 zcmZ2!z0!Ju5+mb8MahXavJkph3PLZJgV6Ui!SrM$MimGnfl(g9n8~OCVccd^g)pR; zpdv9$@@xm}85kHqMo*r_1Tky!B_^m=Zf0eO4i9E=2&0l&8p2q|tOsFyV{V2pCbK}C zH2F9S#I2K=S#=;%o~$wuMm;N3&1P1pIWJhDR;aQ;4a{YON-YA3Ouoow57Dc|4mCE7 zT>>I9gB@zx8Fr{%5e{fDgo7B98#$aHD(`X_LKqsHiV#LJCsglrPIZXL4NgeVPUh!= n2B9w()cupWqS+ek|NjStlkjAAZU;uj%^ut@7=e@_Z-oE=9Zg{{ delta 375 zcmZ2!z0!Ju(&S88sfjkSV5(ROOf8oKQ};C|SMW+rR$^2E(+Q07V0tE_2AIChs0yZ~ zm^3DPibze4VUnMGf>(a>EGDq_$(Mk9pxKkTnU%q`2eUYsu4I-5)9aY^Cf5o}P5#E* z4CYT}0oy+LI1AWKlbKm{!1A7~GGO_7R*3v&R*3!=tPpcm*&ycRvO&Zb0r?u?Jp=b`7Vbc*nSO8MX))^oDhA} zIn}}Z8=T-ko6OGz2_IiB9kBRhu4onphX4O3Gct)zX6JTbWZ3M%{elrBx7mv~UH|}M C=W`nX diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity index 1cce48d..bcfad57 100644 --- a/Assets/Scenes/SampleScene.unity +++ b/Assets/Scenes/SampleScene.unity @@ -860,7 +860,7 @@ MonoBehaviour: m_Arguments: m_ObjectArgument: {fileID: 0} m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine - m_IntArgument: 48 + m_IntArgument: 11 m_FloatArgument: 0 m_StringArgument: m_BoolArgument: 0 @@ -1070,6 +1070,7 @@ RectTransform: m_LocalScale: {x: 0, y: 0, z: 0} m_ConstrainProportionsScale: 0 m_Children: + - {fileID: 1987857384} - {fileID: 1394234348} - {fileID: 1161878326} - {fileID: 392790004} @@ -1396,6 +1397,98 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1798358786} m_CullTransparentMesh: 1 +--- !u!1 &1987857383 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1987857384} + - component: {fileID: 1987857386} + - component: {fileID: 1987857385} + - component: {fileID: 1987857387} + m_Layer: 5 + m_Name: AudioSystemStatus + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1987857384 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1987857383} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1667985901} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 200, y: 300} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &1987857385 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1987857383} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 18 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 1 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Audio System Status +--- !u!222 &1987857386 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1987857383} + m_CullTransparentMesh: 1 +--- !u!114 &1987857387 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1987857383} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 393e3f1fc2824bcf81260ccf46ce9524, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1 &2093584669 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/OCES/Audio/HandWritten/AudioScheduler.cs b/Assets/Scripts/OCES/Audio/HandWritten/AudioScheduler.cs index 757d617..a401448 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/AudioScheduler.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/AudioScheduler.cs @@ -11,6 +11,8 @@ namespace OCES.Audio /// public class AudioScheduler : MonoBehaviour { + public UnityEngine.UI.Text audioSystemTextBox; + const int k_maxGlobalConcurrent = 128; //记录某个 AudioObject 最近一次触发播放的时刻,用于 MinInterval 节流判断,是"上次什么时候播过"。 @@ -18,7 +20,7 @@ namespace OCES.Audio readonly Dictionary m_clipConcurrentCount = new(); readonly List m_activeSounds = new(); - // 复用列表,避免 TryPlay 每帧分配临时 List(原 LINQ .Where().ToList()) + // 复用列表,避免 TryPlay 每帧分配临时 List readonly List m_tempSameObject = new(); readonly List m_tempSameGroup = new(); readonly List m_tempLowerPriority = new(); @@ -31,6 +33,14 @@ namespace OCES.Audio AudioContainerSelector m_containerSelector; PitchStepManager m_pitchStepManager; +#if UNITY_EDITOR + void Update() + { + Editor.DebugInfoCollector.Instance.ActiveSounds = this.m_activeSounds; + Editor.DebugInfoCollector.Instance.ClipConcurrentCount = this.m_clipConcurrentCount; + } +#endif + int GetClipCount(uint id) { @@ -40,7 +50,7 @@ namespace OCES.Audio void IncrementClipCount(uint id) { this.m_clipConcurrentCount[id] = GetClipCount(id) + 1; - //Debug.Log($"{id} count added to {GetClipCount(id)}"); + Debug.Log($"{id} count added to {GetClipCount(id)}"); } void DecrementClipCount(uint id) @@ -167,45 +177,24 @@ namespace OCES.Audio void PlayNewSound(AudioObject audioObject, float pitch) { - // Blend:同时播放所有音轨,无需走后续逻辑 - if (audioObject.ContainerType == ContainerType.Blend) + ActiveSound active = new() { - for (int i = 0; i < audioObject.Name.Count; i++) - ConfigureSource(this.m_pool.AcquireAudioSource(), audioObject, pitch, clipIndex: i, registerRemove: true); - return; - - // TODO BlendRanges, BlendCrossFadeType, BlendReactParam 支持 - } - - AudioSource source = this.m_pool.AcquireAudioSource(); - - // 持续播放模式(Continuous) - if (audioObject.Name.Count > 1 && audioObject.ContainerPlayMode) - { - ActiveSound chainActive = new() - { - Source = source, - AudioObject = audioObject, - StartTime = Time.realtimeSinceStartupAsDouble, - Pitch = pitch, - }; - this.m_activeSounds.Add(chainActive); - IncrementClipCount(audioObject.Id); - int continuousStart = audioObject.ContainerType == ContainerType.Random ? -1 : 0; - chainActive.Coroutine = - StartCoroutine(PlayContainerContinuous(source, audioObject, chainActive, continuousStart, pitch)); - return; - } - - // 单次播放(步进模式) - int startIndex = audioObject.ContainerType switch - { - ContainerType.Random => this.m_containerSelector.PickShuffleIndex(audioObject), - ContainerType.Sequence => this.m_containerSelector.GetNextSequenceIndex(audioObject), - _ => 0, + AudioObject = audioObject, + Pitch = pitch, + State = ActiveSoundState.Pending, + StartTime = Time.realtimeSinceStartupAsDouble, }; - - ConfigureSource(source, audioObject, pitch, startIndex, registerRemove: true); + + if (audioObject.InitialDelay > 0) + { + this.m_activeSounds.Add(active); + IncrementClipCount(audioObject.Id); + + active.Coroutine = StartCoroutine(PlayAfterDelay(active, audioObject, pitch)); + return; + } + + ExecutePlay(active); } /// @@ -233,11 +222,13 @@ namespace OCES.Audio limitRepetition); // 配置并播放 - if (!ConfigureSource(source, audioObject, pitch, index, registerRemove: false)) + if (!SetupSource(source, audioObject, pitch, index)) { Debug.LogError($"音频文件未找到:{audioObject.Name[index]}"); yield break; } + + StartPlayback(source); yield return new WaitWhile(() => source.isPlaying); @@ -261,6 +252,20 @@ namespace OCES.Audio } } } + static void StartPlayback(AudioSource source) + { + source.Play(); + } + + IEnumerator PlayAfterDelay(ActiveSound active, AudioObject audioObject, float pitch) + { + Debug.Log($"Delaying for {audioObject.InitialDelay} second(s)."); + yield return new WaitForSeconds(audioObject.InitialDelay); + + if (!this.m_activeSounds.Contains(active)) yield break; + + ExecutePlay(active, isRegistered: true); + } // ───────────────────────────────────────────── // 工具方法 @@ -312,42 +317,121 @@ namespace OCES.Audio _ => this.m_sfxGroup, }; - - bool ConfigureSource(AudioSource source, AudioObject audioObject, float pitch, int clipIndex = 0, bool registerRemove = true) + bool SetupSource(AudioSource source, AudioObject audioObject, float pitch, int clipIndex = 0) { - // TODO 现用现找可能会导致主线程卡死,尤其是低端机。需要配合Decompress配置优化性能。 - AudioClip clip = Resources.Load($"Audios/{audioObject.Name[clipIndex]}"); + AudioClip clip = Resources.Load($"Audios/{audioObject.Name[clipIndex]}"); // TODO 抽象同一资源加载接口 if (!clip) { Debug.LogError($"音频文件未找到:{audioObject.Name[clipIndex]}"); return false; } - source.clip = clip; - source.loop = audioObject.LoopCount < 0; + source.clip = clip; + source.loop = audioObject.LoopCount < 0; source.priority = audioObject.Priority; source.outputAudioMixerGroup = GetMixerGroup(audioObject.MixingType); source.pitch = pitch; - source.Play(); - - if (registerRemove) - { - IncrementClipCount(audioObject.Id); - - ActiveSound active = new() - { - Source = source, - AudioObject = audioObject, - StartTime = Time.realtimeSinceStartupAsDouble, - Pitch = pitch, - }; - this.m_activeSounds.Add(active); - active.Coroutine = StartCoroutine(RemoveWhenFinished(active)); - } return true; } + void RegisterActiveSound(ActiveSound activeSound, AudioSource audioSource, bool isRegistered = false) + { + activeSound.Source = audioSource; + activeSound.State = ActiveSoundState.Playing; + activeSound.StartTime = Time.realtimeSinceStartupAsDouble; + + if (!isRegistered) + { + this.m_activeSounds.Add(activeSound); + IncrementClipCount(activeSound.AudioObject.Id); + } + + activeSound.Coroutine = StartCoroutine(RemoveWhenFinished(activeSound)); + } + + void ExecutePlay(ActiveSound active, bool isRegistered = false) + { + AudioObject audioObject = active.AudioObject; + float pitch = active.Pitch; + + // ======================= + // Blend(每个clip一个ActiveSound) + // ======================= + if (audioObject.ContainerType == ContainerType.Blend) + { + for (int i = 0; i < audioObject.Name.Count; i++) + { + AudioSource source = this.m_pool.AcquireAudioSource(); + + ActiveSound child = new() + { + AudioObject = audioObject, + Pitch = pitch, + State = ActiveSoundState.Playing + }; + + if (!SetupSource(source, audioObject, pitch, i)) + { + this.m_pool.ReturnToPool(source.gameObject); + continue; + } + + StartPlayback(source); + RegisterActiveSound(child, source); + } + + // 删除 pending 占位 + if (this.m_activeSounds.Contains(active)) + { + DecrementClipCount(audioObject.Id); + this.m_activeSounds.Remove(active); + } + + return; + } + + AudioSource sourceSingle = this.m_pool.AcquireAudioSource(); + + // ======================= + // Continuous + // ======================= + if (audioObject.Name.Count > 1 && audioObject.ContainerPlayMode) + { + active.Source = sourceSingle; + active.State = ActiveSoundState.Playing; + + this.m_activeSounds.Add(active); + IncrementClipCount(audioObject.Id); + + int start = audioObject.ContainerType == ContainerType.Random ? -1 : 0; + + active.Coroutine = StartCoroutine( + PlayContainerContinuous(sourceSingle, audioObject, active, start, pitch) + ); + + return; + } + + // ======================= + // 单次播放 + // ======================= + int index = audioObject.ContainerType switch + { + ContainerType.Random => m_containerSelector.PickShuffleIndex(audioObject), + ContainerType.Sequence => m_containerSelector.GetNextSequenceIndex(audioObject), + _ => 0 + }; + + if (!SetupSource(sourceSingle, audioObject, pitch, index)) + { + m_pool.ReturnToPool(sourceSingle.gameObject); + return; + } + + StartPlayback(sourceSingle); + RegisterActiveSound(active, sourceSingle, isRegistered); + } IEnumerator RemoveWhenFinished(ActiveSound active) { if (active.AudioObject.LoopCount < 0) @@ -372,7 +456,7 @@ namespace OCES.Audio bool PlayAgain(ActiveSound active) { - active.Source.Play(); + StartPlayback(active.Source); return true; } @@ -384,7 +468,7 @@ namespace OCES.Audio //Debug.Log($"[StopSound] 协程已终止: {active.AudioObject.Name[0]}"); } - active.Source.Stop(); + if(active.Source) active.Source.Stop(); DecrementClipCount(active.AudioObject.Id); this.m_activeSounds.Remove(active); this.m_pool.ReturnToPool(active.Source.gameObject); @@ -405,5 +489,6 @@ namespace OCES.Audio public int CurrentLoopCount; public Coroutine Coroutine; public float Pitch; + public ActiveSoundState State; } } \ No newline at end of file diff --git a/Assets/Scripts/OCES/Audio/HandWritten/HandWrittenDefinitions.cs b/Assets/Scripts/OCES/Audio/HandWritten/HandWrittenDefinitions.cs index 8a8dbbb..57693c3 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/HandWrittenDefinitions.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/HandWrittenDefinitions.cs @@ -57,6 +57,13 @@ namespace OCES.Audio Bass, } + public enum ActiveSoundState + { + Pending, // 已进入调度,但还没真正播放 + Playing, // 已经开始播放 + Finished, + } + public interface IBinarySerializable { void DeSerialize(BinaryReader reader); diff --git a/Assets/Scripts/OCES/Audio/HandWritten/LongAudio.meta b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio.meta new file mode 100644 index 0000000..9717091 --- /dev/null +++ b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 79201b50e9334e9b8ebb35186b5df5e4 +timeCreated: 1774421407 \ No newline at end of file diff --git a/Assets/Scripts/OCES/Audio/HandWritten/AmbienceChannelPlayer.cs b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/AmbienceChannelPlayer.cs similarity index 80% rename from Assets/Scripts/OCES/Audio/HandWritten/AmbienceChannelPlayer.cs rename to Assets/Scripts/OCES/Audio/HandWritten/LongAudio/AmbienceChannelPlayer.cs index d290964..25438d3 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/AmbienceChannelPlayer.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/AmbienceChannelPlayer.cs @@ -15,6 +15,8 @@ namespace OCES.Audio ContainerPlayHandle m_currentHandle; Coroutine m_transitionCoroutine; + Coroutine m_currentFadeOutCoroutine; + Coroutine m_currentFadeInCoroutine; uint m_currentContainerId; @@ -60,14 +62,31 @@ namespace OCES.Audio IEnumerator DoTransition(uint newContainerId, AmbienceTransition transition) { + if (newContainerId == this.m_fader.CurrentContainerId && this.m_fader.CurrentHandle != null) yield break; + // 如果等待期间被切回来了,就不淡变了 + + if (this.m_currentFadeInCoroutine != null) + { + this.m_coroutineHost.StopCoroutine(this.m_currentFadeInCoroutine); + this.m_currentFadeInCoroutine = null; + } + + if (this.m_currentFadeOutCoroutine != null) + { + this.m_coroutineHost.StopCoroutine(this.m_currentFadeOutCoroutine); + this.m_currentFadeOutCoroutine = null; + } + ContainerPlayHandle outgoing = this.m_fader.CurrentHandle; float outgoingVolume = this.m_fader.CurrentVolume; - this.m_coroutineHost.StartCoroutine( + this.m_currentFadeOutCoroutine = this.m_coroutineHost.StartCoroutine( this.m_fader.FadeOutBranch(outgoing, outgoingVolume, transition)); - yield return this.m_coroutineHost.StartCoroutine( + this.m_currentFadeInCoroutine = this.m_coroutineHost.StartCoroutine( this.m_fader.FadeInBranch(newContainerId, transition)); + yield return this.m_currentFadeInCoroutine; + this.m_currentFadeInCoroutine = null; } // ───────────────────────────────────────────── diff --git a/Assets/Scripts/OCES/Audio/HandWritten/AmbienceChannelPlayer.cs.meta b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/AmbienceChannelPlayer.cs.meta similarity index 100% rename from Assets/Scripts/OCES/Audio/HandWritten/AmbienceChannelPlayer.cs.meta rename to Assets/Scripts/OCES/Audio/HandWritten/LongAudio/AmbienceChannelPlayer.cs.meta diff --git a/Assets/Scripts/OCES/Audio/HandWritten/AudioContainerSelector.cs b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/AudioContainerSelector.cs similarity index 100% rename from Assets/Scripts/OCES/Audio/HandWritten/AudioContainerSelector.cs rename to Assets/Scripts/OCES/Audio/HandWritten/LongAudio/AudioContainerSelector.cs diff --git a/Assets/Scripts/OCES/Audio/HandWritten/AudioContainerSelector.cs.meta b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/AudioContainerSelector.cs.meta similarity index 100% rename from Assets/Scripts/OCES/Audio/HandWritten/AudioContainerSelector.cs.meta rename to Assets/Scripts/OCES/Audio/HandWritten/LongAudio/AudioContainerSelector.cs.meta diff --git a/Assets/Scripts/OCES/Audio/HandWritten/ChannelFader.cs b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/ChannelFader.cs similarity index 96% rename from Assets/Scripts/OCES/Audio/HandWritten/ChannelFader.cs rename to Assets/Scripts/OCES/Audio/HandWritten/LongAudio/ChannelFader.cs index 6c46008..b393b21 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/ChannelFader.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/ChannelFader.cs @@ -69,7 +69,7 @@ namespace OCES.Audio /// internal IEnumerator FadeInBranch(uint newContainerId, ITransitionConfig transition, Action onContainerStarted = null) { - if (transition?.FadeOutOffset > 0f) + if (transition?.FadeInOffset > 0f) { //Debug.Log($"Waiting {transition.FadeInOffset} to fade in."); yield return new WaitForSeconds(transition.FadeInOffset); @@ -82,10 +82,11 @@ namespace OCES.Audio yield break; } - float startVolume = transition?.FadeOutOffset > 0f ? 0f : 1f; + float startVolume = transition?.FadeInTime > 0f ? 0f : 1f; StartNew(newContainerId, startVolume); - - if (transition?.FadeOutOffset > 0f) + onContainerStarted?.Invoke(); + + if (transition?.FadeInTime > 0f) { yield return this.m_coroutineHost.StartCoroutine( FadeIn(CurrentHandle, transition.FadeInTime)); diff --git a/Assets/Scripts/OCES/Audio/HandWritten/ChannelFader.cs.meta b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/ChannelFader.cs.meta similarity index 100% rename from Assets/Scripts/OCES/Audio/HandWritten/ChannelFader.cs.meta rename to Assets/Scripts/OCES/Audio/HandWritten/LongAudio/ChannelFader.cs.meta diff --git a/Assets/Scripts/OCES/Audio/HandWritten/MusicChannelPlayer.cs b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicChannelPlayer.cs similarity index 87% rename from Assets/Scripts/OCES/Audio/HandWritten/MusicChannelPlayer.cs rename to Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicChannelPlayer.cs index f7bb44d..1fe6b19 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/MusicChannelPlayer.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicChannelPlayer.cs @@ -13,6 +13,9 @@ namespace OCES.Audio readonly MusicTransitionConfig m_transitionConfig; readonly MonoBehaviour m_coroutineHost; readonly ChannelFader m_fader; + + Coroutine m_currentFadeInCoroutine; + Coroutine m_currentFadeOutCoroutine; // 当前正在播放的句柄 ContainerPlayHandle m_currentHandle; @@ -79,6 +82,18 @@ namespace OCES.Audio IEnumerator DoTransition(uint newContainerId, MusicTransition transition) { + if (this.m_currentFadeInCoroutine != null) + { + this.m_coroutineHost.StopCoroutine(this.m_currentFadeInCoroutine); + this.m_currentFadeInCoroutine = null; + } + + if (this.m_currentFadeOutCoroutine != null) + { + this.m_coroutineHost.StopCoroutine(this.m_currentFadeOutCoroutine); + this.m_currentFadeOutCoroutine = null; + } + // ── 1. 等待节拍对齐(由 Transition 的 AlignMode 决定)── if (transition != null && this.m_currentContainer != null) { @@ -87,13 +102,16 @@ namespace OCES.Audio } // ── 2 & 3. 淡出与淡入并行:两条分支从同一时刻起算各自的 Offset,互不等待 ── + if (newContainerId == this.m_fader.CurrentContainerId && this.m_fader.CurrentHandle != null) yield break; + // 如果等待期间被切回来了,就不淡变了 + ContainerPlayHandle outgoing = this.m_fader.CurrentHandle; - float outVol = this.m_fader.CurrentVolume; + float outVol = this.m_fader.CurrentVolume; - this.m_coroutineHost.StartCoroutine( + this.m_currentFadeOutCoroutine = this.m_coroutineHost.StartCoroutine( this.m_fader.FadeOutBranch(outgoing, outVol, transition)); - yield return this.m_coroutineHost.StartCoroutine( + this.m_currentFadeInCoroutine = this.m_coroutineHost.StartCoroutine( this.m_fader.FadeInBranch(newContainerId, transition, onContainerStarted: () => { @@ -101,6 +119,8 @@ namespace OCES.Audio this.m_currentContainer = this.m_containerConfig.QueryById(newContainerId); this.m_playStartTime = AudioSettings.dspTime; })); + yield return this.m_currentFadeInCoroutine; + this.m_currentFadeInCoroutine = null; } // ───────────────────────────────────────────── diff --git a/Assets/Scripts/OCES/Audio/HandWritten/MusicChannelPlayer.cs.meta b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicChannelPlayer.cs.meta similarity index 100% rename from Assets/Scripts/OCES/Audio/HandWritten/MusicChannelPlayer.cs.meta rename to Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicChannelPlayer.cs.meta diff --git a/Assets/Scripts/OCES/Audio/HandWritten/MusicContainerPlayer.cs b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicContainerPlayer.cs similarity index 99% rename from Assets/Scripts/OCES/Audio/HandWritten/MusicContainerPlayer.cs rename to Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicContainerPlayer.cs index ccced6c..558f8a1 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/MusicContainerPlayer.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicContainerPlayer.cs @@ -18,6 +18,7 @@ namespace OCES.Audio readonly MonoBehaviour m_coroutineHost; UnityEngine.Audio.AudioMixerGroup m_mixerGroup; + // Sequence Step 模式的全局游标,key = containerId readonly Dictionary m_sequenceStepIndex = new(); diff --git a/Assets/Scripts/OCES/Audio/HandWritten/MusicContainerPlayer.cs.meta b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicContainerPlayer.cs.meta similarity index 100% rename from Assets/Scripts/OCES/Audio/HandWritten/MusicContainerPlayer.cs.meta rename to Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicContainerPlayer.cs.meta diff --git a/Assets/Scripts/OCES/Audio/HandWritten/MusicStateRouter.cs b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicStateRouter.cs similarity index 98% rename from Assets/Scripts/OCES/Audio/HandWritten/MusicStateRouter.cs rename to Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicStateRouter.cs index 3585a20..84f773f 100644 --- a/Assets/Scripts/OCES/Audio/HandWritten/MusicStateRouter.cs +++ b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicStateRouter.cs @@ -39,6 +39,10 @@ namespace OCES.Audio LastMusicPathId = musicPathId; LastAmbiencePathId = ambiencePathId; + +#if UNITY_EDITOR + Editor.DebugInfoCollector.Instance.ActiveStates = this.m_activeStates; +#endif } // ───────────────────────────────────────────── diff --git a/Assets/Scripts/OCES/Audio/HandWritten/MusicStateRouter.cs.meta b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicStateRouter.cs.meta similarity index 100% rename from Assets/Scripts/OCES/Audio/HandWritten/MusicStateRouter.cs.meta rename to Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicStateRouter.cs.meta diff --git a/Assets/Scripts/OCES/Audio/HandWritten/MusicSystem.cs b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicSystem.cs similarity index 100% rename from Assets/Scripts/OCES/Audio/HandWritten/MusicSystem.cs rename to Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicSystem.cs diff --git a/Assets/Scripts/OCES/Audio/HandWritten/MusicSystem.cs.meta b/Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicSystem.cs.meta similarity index 100% rename from Assets/Scripts/OCES/Audio/HandWritten/MusicSystem.cs.meta rename to Assets/Scripts/OCES/Audio/HandWritten/LongAudio/MusicSystem.cs.meta