e032f7687f
修复FadeIn读取了FadeOut参数的问题。 增加Initial Delay功能。 重构AudioScheduler.ConfigureSource() -> SetupSource(), RegisterActiveSound(), StartPlayBack()。 移动长音频相关功能至LongAudio文件夹。
148 lines
5.3 KiB
C#
148 lines
5.3 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
|
|
namespace OCES.Audio
|
|
{
|
|
public class AudioContainerSelector
|
|
{
|
|
// TODO: 根据 audioObject.ContainerScope 控制随机历史的共享范围:
|
|
// - Global(当前实现):同一 AudioObject 的所有并发实例共享同一份 playHistory 和 limitRepetition 队列,
|
|
// 不放回随机在全局层面生效,并发实例之间互相感知已播放记录。
|
|
// - PerInstance:每个并发播放实例持有独立的 playHistory 和 limitRepetition 队列,
|
|
// 不放回随机仅在该实例内生效,实例之间完全隔离。
|
|
// 实现思路:PerInstance 模式下将 HashSet/Queue 作为局部变量传入协程,不再写入这两个 Dictionary。
|
|
readonly Dictionary<uint, HashSet<int>> m_randomPlayedHistories = new();
|
|
readonly Dictionary<uint, Queue<int>> m_randomRecentQueues = new();
|
|
readonly Dictionary<uint, int> m_sequenceNextIndex = new();
|
|
|
|
|
|
/// <summary>
|
|
/// Shuffle 随机模式下选取 index(支持 LimitRepetition 队列)
|
|
/// </summary>
|
|
public int PickShuffleIndex(AudioObject audioObject)
|
|
{
|
|
int count = audioObject.Name.Count;
|
|
|
|
// LimitRepetition 队列
|
|
int limitRepetition = Mathf.Clamp(audioObject.LimitRepetition, 0, count - 1);
|
|
if (!this.m_randomRecentQueues.TryGetValue(audioObject.Id, out Queue<int> recent))
|
|
{
|
|
recent = new Queue<int>();
|
|
this.m_randomRecentQueues[audioObject.Id] = recent;
|
|
}
|
|
|
|
if (!audioObject.RandomType)
|
|
{
|
|
List<int> candidates = Enumerable.Range(0, count)
|
|
.Where(i => !recent.Contains(i))
|
|
.ToList();
|
|
|
|
if (candidates.Count == 0)
|
|
candidates = Enumerable.Range(0, count).ToList();
|
|
|
|
int chosen = candidates[Random.Range(0, candidates.Count)];
|
|
|
|
if (limitRepetition > 0)
|
|
{
|
|
recent.Enqueue(chosen);
|
|
if (recent.Count > limitRepetition)
|
|
recent.Dequeue();
|
|
}
|
|
|
|
return chosen;
|
|
}
|
|
|
|
// 不放回随机
|
|
if (!this.m_randomPlayedHistories.TryGetValue(audioObject.Id, out HashSet<int> history))
|
|
{
|
|
history = new HashSet<int>();
|
|
this.m_randomPlayedHistories[audioObject.Id] = history;
|
|
}
|
|
|
|
List<int> available = Enumerable.Range(0, count)
|
|
.Where(i => !history.Contains(i) && !recent.Contains(i))
|
|
.ToList();
|
|
|
|
if (available.Count == 0)
|
|
{
|
|
history.Clear();
|
|
available = Enumerable.Range(0, count)
|
|
.Where(i => !recent.Contains(i))
|
|
.ToList();
|
|
|
|
if (available.Count == 0)
|
|
available = Enumerable.Range(0, count).ToList();
|
|
}
|
|
|
|
int chosenIndex = available[Random.Range(0, available.Count)];
|
|
history.Add(chosenIndex);
|
|
|
|
if (limitRepetition > 0)
|
|
{
|
|
recent.Enqueue(chosenIndex);
|
|
if (recent.Count > limitRepetition)
|
|
recent.Dequeue();
|
|
}
|
|
|
|
return chosenIndex;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 连续容器的 Random 模式下,带 LimitRepetition 逻辑地选取 index
|
|
/// </summary>
|
|
public int PickNextRandomIndex(AudioObject audioObject, List<int> remainingPool, Queue<int> recentPlayed, int limitRepetition)
|
|
{
|
|
if (!this.m_randomPlayedHistories.TryGetValue(audioObject.Id, out HashSet<int> history))
|
|
{
|
|
history = new HashSet<int>();
|
|
this.m_randomPlayedHistories[audioObject.Id] = history;
|
|
}
|
|
|
|
List<int> candidates = remainingPool
|
|
.Where(i => !recentPlayed.Contains(i))
|
|
.ToList();
|
|
|
|
if (candidates.Count == 0)
|
|
candidates = new List<int>(remainingPool);
|
|
|
|
int index = candidates[Random.Range(0, candidates.Count)];
|
|
|
|
if (audioObject.RandomType)
|
|
remainingPool.Remove(index);
|
|
|
|
if (limitRepetition > 0)
|
|
recentPlayed.Enqueue(index);
|
|
|
|
if (recentPlayed.Count > limitRepetition)
|
|
recentPlayed.Dequeue();
|
|
|
|
history.Add(index);
|
|
return index;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取 Sequence 模式下的当前 index 并推进游标
|
|
/// </summary>
|
|
public int GetNextSequenceIndex(AudioObject audioObject)
|
|
{
|
|
int current = this.m_sequenceNextIndex.GetValueOrDefault(audioObject.Id, 0);
|
|
this.m_sequenceNextIndex[audioObject.Id] = (current + 1) % audioObject.Name.Count;
|
|
return current;
|
|
}
|
|
|
|
public void ResetHistory(uint id)
|
|
{
|
|
if (this.m_randomPlayedHistories.TryGetValue(id, out HashSet<int> history))
|
|
{
|
|
history.Clear();
|
|
}
|
|
}
|
|
|
|
public int GetHistoryCount(uint id)
|
|
{
|
|
return this.m_randomPlayedHistories.TryGetValue(id, out HashSet<int> history) ? history.Count : 0;
|
|
}
|
|
}
|
|
}
|