解决重复切换State的时候会导致重复播放对应Segment的问题。
修复FadeIn读取了FadeOut参数的问题。 增加Initial Delay功能。 重构AudioScheduler.ConfigureSource() -> SetupSource(), RegisterActiveSound(), StartPlayBack()。 移动长音频相关功能至LongAudio文件夹。
This commit is contained in:
Binary file not shown.
@@ -860,7 +860,7 @@ MonoBehaviour:
|
|||||||
m_Arguments:
|
m_Arguments:
|
||||||
m_ObjectArgument: {fileID: 0}
|
m_ObjectArgument: {fileID: 0}
|
||||||
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
|
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
|
||||||
m_IntArgument: 48
|
m_IntArgument: 11
|
||||||
m_FloatArgument: 0
|
m_FloatArgument: 0
|
||||||
m_StringArgument:
|
m_StringArgument:
|
||||||
m_BoolArgument: 0
|
m_BoolArgument: 0
|
||||||
@@ -1070,6 +1070,7 @@ RectTransform:
|
|||||||
m_LocalScale: {x: 0, y: 0, z: 0}
|
m_LocalScale: {x: 0, y: 0, z: 0}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children:
|
m_Children:
|
||||||
|
- {fileID: 1987857384}
|
||||||
- {fileID: 1394234348}
|
- {fileID: 1394234348}
|
||||||
- {fileID: 1161878326}
|
- {fileID: 1161878326}
|
||||||
- {fileID: 392790004}
|
- {fileID: 392790004}
|
||||||
@@ -1396,6 +1397,98 @@ CanvasRenderer:
|
|||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 1798358786}
|
m_GameObject: {fileID: 1798358786}
|
||||||
m_CullTransparentMesh: 1
|
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
|
--- !u!1 &2093584669
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ namespace OCES.Audio
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class AudioScheduler : MonoBehaviour
|
public class AudioScheduler : MonoBehaviour
|
||||||
{
|
{
|
||||||
|
public UnityEngine.UI.Text audioSystemTextBox;
|
||||||
|
|
||||||
const int k_maxGlobalConcurrent = 128;
|
const int k_maxGlobalConcurrent = 128;
|
||||||
|
|
||||||
//记录某个 AudioObject 最近一次触发播放的时刻,用于 MinInterval 节流判断,是"上次什么时候播过"。
|
//记录某个 AudioObject 最近一次触发播放的时刻,用于 MinInterval 节流判断,是"上次什么时候播过"。
|
||||||
@@ -18,7 +20,7 @@ namespace OCES.Audio
|
|||||||
readonly Dictionary<uint, int> m_clipConcurrentCount = new();
|
readonly Dictionary<uint, int> m_clipConcurrentCount = new();
|
||||||
readonly List<ActiveSound> m_activeSounds = new();
|
readonly List<ActiveSound> m_activeSounds = new();
|
||||||
|
|
||||||
// 复用列表,避免 TryPlay 每帧分配临时 List(原 LINQ .Where().ToList())
|
// 复用列表,避免 TryPlay 每帧分配临时 List
|
||||||
readonly List<ActiveSound> m_tempSameObject = new();
|
readonly List<ActiveSound> m_tempSameObject = new();
|
||||||
readonly List<ActiveSound> m_tempSameGroup = new();
|
readonly List<ActiveSound> m_tempSameGroup = new();
|
||||||
readonly List<ActiveSound> m_tempLowerPriority = new();
|
readonly List<ActiveSound> m_tempLowerPriority = new();
|
||||||
@@ -31,6 +33,14 @@ namespace OCES.Audio
|
|||||||
AudioContainerSelector m_containerSelector;
|
AudioContainerSelector m_containerSelector;
|
||||||
PitchStepManager m_pitchStepManager;
|
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)
|
int GetClipCount(uint id)
|
||||||
{
|
{
|
||||||
@@ -40,7 +50,7 @@ namespace OCES.Audio
|
|||||||
void IncrementClipCount(uint id)
|
void IncrementClipCount(uint id)
|
||||||
{
|
{
|
||||||
this.m_clipConcurrentCount[id] = GetClipCount(id) + 1;
|
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)
|
void DecrementClipCount(uint id)
|
||||||
@@ -167,45 +177,24 @@ namespace OCES.Audio
|
|||||||
|
|
||||||
void PlayNewSound(AudioObject audioObject, float pitch)
|
void PlayNewSound(AudioObject audioObject, float pitch)
|
||||||
{
|
{
|
||||||
// Blend:同时播放所有音轨,无需走后续逻辑
|
ActiveSound active = new()
|
||||||
if (audioObject.ContainerType == ContainerType.Blend)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < audioObject.Name.Count; i++)
|
AudioObject = audioObject,
|
||||||
ConfigureSource(this.m_pool.AcquireAudioSource(), audioObject, pitch, clipIndex: i, registerRemove: true);
|
Pitch = pitch,
|
||||||
return;
|
State = ActiveSoundState.Pending,
|
||||||
|
StartTime = Time.realtimeSinceStartupAsDouble,
|
||||||
// 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,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -233,12 +222,14 @@ namespace OCES.Audio
|
|||||||
limitRepetition);
|
limitRepetition);
|
||||||
|
|
||||||
// 配置并播放
|
// 配置并播放
|
||||||
if (!ConfigureSource(source, audioObject, pitch, index, registerRemove: false))
|
if (!SetupSource(source, audioObject, pitch, index))
|
||||||
{
|
{
|
||||||
Debug.LogError($"音频文件未找到:{audioObject.Name[index]}");
|
Debug.LogError($"音频文件未找到:{audioObject.Name[index]}");
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StartPlayback(source);
|
||||||
|
|
||||||
yield return new WaitWhile(() => source.isPlaying);
|
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,
|
_ => this.m_sfxGroup,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool SetupSource(AudioSource source, AudioObject audioObject, float pitch, int clipIndex = 0)
|
||||||
bool ConfigureSource(AudioSource source, AudioObject audioObject, float pitch, int clipIndex = 0, bool registerRemove = true)
|
|
||||||
{
|
{
|
||||||
// TODO 现用现找可能会导致主线程卡死,尤其是低端机。需要配合Decompress配置优化性能。
|
AudioClip clip = Resources.Load<AudioClip>($"Audios/{audioObject.Name[clipIndex]}"); // TODO 抽象同一资源加载接口
|
||||||
AudioClip clip = Resources.Load<AudioClip>($"Audios/{audioObject.Name[clipIndex]}");
|
|
||||||
if (!clip)
|
if (!clip)
|
||||||
{
|
{
|
||||||
Debug.LogError($"音频文件未找到:{audioObject.Name[clipIndex]}");
|
Debug.LogError($"音频文件未找到:{audioObject.Name[clipIndex]}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
source.clip = clip;
|
source.clip = clip;
|
||||||
source.loop = audioObject.LoopCount < 0;
|
source.loop = audioObject.LoopCount < 0;
|
||||||
source.priority = audioObject.Priority;
|
source.priority = audioObject.Priority;
|
||||||
source.outputAudioMixerGroup = GetMixerGroup(audioObject.MixingType);
|
source.outputAudioMixerGroup = GetMixerGroup(audioObject.MixingType);
|
||||||
source.pitch = pitch;
|
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;
|
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)
|
IEnumerator RemoveWhenFinished(ActiveSound active)
|
||||||
{
|
{
|
||||||
if (active.AudioObject.LoopCount < 0)
|
if (active.AudioObject.LoopCount < 0)
|
||||||
@@ -372,7 +456,7 @@ namespace OCES.Audio
|
|||||||
|
|
||||||
bool PlayAgain(ActiveSound active)
|
bool PlayAgain(ActiveSound active)
|
||||||
{
|
{
|
||||||
active.Source.Play();
|
StartPlayback(active.Source);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,7 +468,7 @@ namespace OCES.Audio
|
|||||||
//Debug.Log($"[StopSound] 协程已终止: {active.AudioObject.Name[0]}");
|
//Debug.Log($"[StopSound] 协程已终止: {active.AudioObject.Name[0]}");
|
||||||
}
|
}
|
||||||
|
|
||||||
active.Source.Stop();
|
if(active.Source) active.Source.Stop();
|
||||||
DecrementClipCount(active.AudioObject.Id);
|
DecrementClipCount(active.AudioObject.Id);
|
||||||
this.m_activeSounds.Remove(active);
|
this.m_activeSounds.Remove(active);
|
||||||
this.m_pool.ReturnToPool(active.Source.gameObject);
|
this.m_pool.ReturnToPool(active.Source.gameObject);
|
||||||
@@ -405,5 +489,6 @@ namespace OCES.Audio
|
|||||||
public int CurrentLoopCount;
|
public int CurrentLoopCount;
|
||||||
public Coroutine Coroutine;
|
public Coroutine Coroutine;
|
||||||
public float Pitch;
|
public float Pitch;
|
||||||
|
public ActiveSoundState State;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,6 +57,13 @@ namespace OCES.Audio
|
|||||||
Bass,
|
Bass,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ActiveSoundState
|
||||||
|
{
|
||||||
|
Pending, // 已进入调度,但还没真正播放
|
||||||
|
Playing, // 已经开始播放
|
||||||
|
Finished,
|
||||||
|
}
|
||||||
|
|
||||||
public interface IBinarySerializable
|
public interface IBinarySerializable
|
||||||
{
|
{
|
||||||
void DeSerialize(BinaryReader reader);
|
void DeSerialize(BinaryReader reader);
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 79201b50e9334e9b8ebb35186b5df5e4
|
||||||
|
timeCreated: 1774421407
|
||||||
+21
-2
@@ -15,6 +15,8 @@ namespace OCES.Audio
|
|||||||
|
|
||||||
ContainerPlayHandle m_currentHandle;
|
ContainerPlayHandle m_currentHandle;
|
||||||
Coroutine m_transitionCoroutine;
|
Coroutine m_transitionCoroutine;
|
||||||
|
Coroutine m_currentFadeOutCoroutine;
|
||||||
|
Coroutine m_currentFadeInCoroutine;
|
||||||
|
|
||||||
uint m_currentContainerId;
|
uint m_currentContainerId;
|
||||||
|
|
||||||
@@ -60,14 +62,31 @@ namespace OCES.Audio
|
|||||||
|
|
||||||
IEnumerator DoTransition(uint newContainerId, AmbienceTransition transition)
|
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;
|
ContainerPlayHandle outgoing = this.m_fader.CurrentHandle;
|
||||||
float outgoingVolume = this.m_fader.CurrentVolume;
|
float outgoingVolume = this.m_fader.CurrentVolume;
|
||||||
|
|
||||||
this.m_coroutineHost.StartCoroutine(
|
this.m_currentFadeOutCoroutine = this.m_coroutineHost.StartCoroutine(
|
||||||
this.m_fader.FadeOutBranch(outgoing, outgoingVolume, transition));
|
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));
|
this.m_fader.FadeInBranch(newContainerId, transition));
|
||||||
|
yield return this.m_currentFadeInCoroutine;
|
||||||
|
this.m_currentFadeInCoroutine = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────
|
// ─────────────────────────────────────────────
|
||||||
+4
-3
@@ -69,7 +69,7 @@ namespace OCES.Audio
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal IEnumerator FadeInBranch(uint newContainerId, ITransitionConfig transition, Action onContainerStarted = null)
|
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.");
|
//Debug.Log($"Waiting {transition.FadeInOffset} to fade in.");
|
||||||
yield return new WaitForSeconds(transition.FadeInOffset);
|
yield return new WaitForSeconds(transition.FadeInOffset);
|
||||||
@@ -82,10 +82,11 @@ namespace OCES.Audio
|
|||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
float startVolume = transition?.FadeOutOffset > 0f ? 0f : 1f;
|
float startVolume = transition?.FadeInTime > 0f ? 0f : 1f;
|
||||||
StartNew(newContainerId, startVolume);
|
StartNew(newContainerId, startVolume);
|
||||||
|
onContainerStarted?.Invoke();
|
||||||
|
|
||||||
if (transition?.FadeOutOffset > 0f)
|
if (transition?.FadeInTime > 0f)
|
||||||
{
|
{
|
||||||
yield return this.m_coroutineHost.StartCoroutine(
|
yield return this.m_coroutineHost.StartCoroutine(
|
||||||
FadeIn(CurrentHandle, transition.FadeInTime));
|
FadeIn(CurrentHandle, transition.FadeInTime));
|
||||||
+24
-4
@@ -14,6 +14,9 @@ namespace OCES.Audio
|
|||||||
readonly MonoBehaviour m_coroutineHost;
|
readonly MonoBehaviour m_coroutineHost;
|
||||||
readonly ChannelFader m_fader;
|
readonly ChannelFader m_fader;
|
||||||
|
|
||||||
|
Coroutine m_currentFadeInCoroutine;
|
||||||
|
Coroutine m_currentFadeOutCoroutine;
|
||||||
|
|
||||||
// 当前正在播放的句柄
|
// 当前正在播放的句柄
|
||||||
ContainerPlayHandle m_currentHandle;
|
ContainerPlayHandle m_currentHandle;
|
||||||
uint m_currentContainerId;
|
uint m_currentContainerId;
|
||||||
@@ -79,6 +82,18 @@ namespace OCES.Audio
|
|||||||
|
|
||||||
IEnumerator DoTransition(uint newContainerId, MusicTransition transition)
|
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 决定)──
|
// ── 1. 等待节拍对齐(由 Transition 的 AlignMode 决定)──
|
||||||
if (transition != null && this.m_currentContainer != null)
|
if (transition != null && this.m_currentContainer != null)
|
||||||
{
|
{
|
||||||
@@ -87,13 +102,16 @@ namespace OCES.Audio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── 2 & 3. 淡出与淡入并行:两条分支从同一时刻起算各自的 Offset,互不等待 ──
|
// ── 2 & 3. 淡出与淡入并行:两条分支从同一时刻起算各自的 Offset,互不等待 ──
|
||||||
ContainerPlayHandle outgoing = this.m_fader.CurrentHandle;
|
if (newContainerId == this.m_fader.CurrentContainerId && this.m_fader.CurrentHandle != null) yield break;
|
||||||
float outVol = this.m_fader.CurrentVolume;
|
// 如果等待期间被切回来了,就不淡变了
|
||||||
|
|
||||||
this.m_coroutineHost.StartCoroutine(
|
ContainerPlayHandle outgoing = this.m_fader.CurrentHandle;
|
||||||
|
float outVol = this.m_fader.CurrentVolume;
|
||||||
|
|
||||||
|
this.m_currentFadeOutCoroutine = this.m_coroutineHost.StartCoroutine(
|
||||||
this.m_fader.FadeOutBranch(outgoing, outVol, transition));
|
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,
|
this.m_fader.FadeInBranch(newContainerId, transition,
|
||||||
onContainerStarted: () =>
|
onContainerStarted: () =>
|
||||||
{
|
{
|
||||||
@@ -101,6 +119,8 @@ namespace OCES.Audio
|
|||||||
this.m_currentContainer = this.m_containerConfig.QueryById(newContainerId);
|
this.m_currentContainer = this.m_containerConfig.QueryById(newContainerId);
|
||||||
this.m_playStartTime = AudioSettings.dspTime;
|
this.m_playStartTime = AudioSettings.dspTime;
|
||||||
}));
|
}));
|
||||||
|
yield return this.m_currentFadeInCoroutine;
|
||||||
|
this.m_currentFadeInCoroutine = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────
|
// ─────────────────────────────────────────────
|
||||||
+1
@@ -18,6 +18,7 @@ namespace OCES.Audio
|
|||||||
readonly MonoBehaviour m_coroutineHost;
|
readonly MonoBehaviour m_coroutineHost;
|
||||||
UnityEngine.Audio.AudioMixerGroup m_mixerGroup;
|
UnityEngine.Audio.AudioMixerGroup m_mixerGroup;
|
||||||
|
|
||||||
|
|
||||||
// Sequence Step 模式的全局游标,key = containerId
|
// Sequence Step 模式的全局游标,key = containerId
|
||||||
readonly Dictionary<uint, int> m_sequenceStepIndex = new();
|
readonly Dictionary<uint, int> m_sequenceStepIndex = new();
|
||||||
|
|
||||||
+4
@@ -39,6 +39,10 @@ namespace OCES.Audio
|
|||||||
|
|
||||||
LastMusicPathId = musicPathId;
|
LastMusicPathId = musicPathId;
|
||||||
LastAmbiencePathId = ambiencePathId;
|
LastAmbiencePathId = ambiencePathId;
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
Editor.DebugInfoCollector.Instance.ActiveStates = this.m_activeStates;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────
|
// ─────────────────────────────────────────────
|
||||||
Reference in New Issue
Block a user