AudioModule

AudioModule
This commit is contained in:
ALEXTANG
2023-04-06 20:32:55 +08:00
parent 3ad9323e9b
commit 4519a3bad0
5 changed files with 217 additions and 85 deletions

View File

@@ -171,24 +171,36 @@ MonoBehaviour:
m_AudioGroupConfigs: m_AudioGroupConfigs:
- m_Name: Music - m_Name: Music
m_Mute: 0 m_Mute: 0
m_Volume: 1 m_Volume: 0.5
m_AgentHelperCount: 1 m_AgentHelperCount: 1
AudioType: 2 AudioType: 2
audioRolloffMode: 1
minDistance: 15
maxDistance: 50
- m_Name: Sound - m_Name: Sound
m_Mute: 0 m_Mute: 0
m_Volume: 1 m_Volume: 0.5
m_AgentHelperCount: 4 m_AgentHelperCount: 4
AudioType: 0 AudioType: 0
audioRolloffMode: 0
minDistance: 1
maxDistance: 500
- m_Name: UISound - m_Name: UISound
m_Mute: 0 m_Mute: 0
m_Volume: 1 m_Volume: 0.5
m_AgentHelperCount: 4 m_AgentHelperCount: 4
AudioType: 1 AudioType: 1
audioRolloffMode: 0
minDistance: 1
maxDistance: 500
- m_Name: Voice - m_Name: Voice
m_Mute: 0 m_Mute: 0
m_Volume: 1 m_Volume: 0.5
m_AgentHelperCount: 1 m_AgentHelperCount: 1
AudioType: 3 AudioType: 3
audioRolloffMode: 0
minDistance: 1
maxDistance: 500
--- !u!1 &43232119 --- !u!1 &43232119
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@@ -5,42 +5,80 @@ using YooAsset;
namespace TEngine namespace TEngine
{ {
/// <summary> /// <summary>
/// 音代理辅助器。 /// 音代理辅助器。
/// </summary> /// </summary>
public class AudioAgent public class AudioAgent
{ {
private AudioModule _audioModule; private AudioModule _audioModule;
private int _id = 0; private int _id;
public AssetOperationHandle assetOperationHandle = null; private AudioSource _source;
private AudioSource _source = null; private AssetOperationHandle _assetOperationHandle;
Transform _transform = null; private Transform _transform;
float _volume = 1.0f; float _volume = 1.0f;
float _duration = 0; float _duration;
float _fadeoutTimer = 0f; private float _fadeoutTimer;
const float FadeoutDuration = 0.2f; private const float FadeoutDuration = 0.2f;
private bool _inPool = false; private bool _inPool;
enum State /// <summary>
/// 音频代理辅助器运行时状态枚举。
/// </summary>
enum RuntimeState
{ {
/// <summary>
/// 无状态。
/// </summary>
None, None,
/// <summary>
/// 加载中状态。
/// </summary>
Loading, Loading,
/// <summary>
/// 播放中状态。
/// </summary>
Playing, Playing,
/// <summary>
/// 渐渐消失状态。
/// </summary>
FadingOut, FadingOut,
/// <summary>
/// 结束状态。
/// </summary>
End, End,
}; };
State _state = State.None; /// <summary>
/// 音频代理辅助器运行时状态。
/// </summary>
RuntimeState _runtimeState = RuntimeState.None;
/// <summary>
/// 音频代理加载请求。
/// </summary>
class LoadRequest class LoadRequest
{ {
public string path; public string Path;
public bool bAsync; public bool BAsync;
} }
/// <summary>
/// 音频代理加载请求。
/// </summary>
LoadRequest _pendingLoad = null; LoadRequest _pendingLoad = null;
/// <summary>
/// AudioSource实例化Id
/// </summary>
public int ID => _id; public int ID => _id;
/// <summary>
/// 资源操作句柄。
/// </summary>
public AssetOperationHandle assetOperationHandle => _assetOperationHandle;
/// <summary>
/// 音频代理辅助器音频大小。
/// </summary>
public float Volume public float Volume
{ {
set set
@@ -54,13 +92,16 @@ namespace TEngine
get => _volume; get => _volume;
} }
public bool IsFinish /// <summary>
/// 音频代理辅助器当前是否空闲。
/// </summary>
public bool IsFree
{ {
get get
{ {
if (_source != null) if (_source != null)
{ {
return _state == State.End; return _runtimeState == RuntimeState.End;
} }
else else
{ {
@@ -69,8 +110,14 @@ namespace TEngine
} }
} }
/// <summary>
/// 音频代理辅助器播放秒数。
/// </summary>
public float Duration => _duration; public float Duration => _duration;
/// <summary>
/// 音频代理辅助器当前音频长度。
/// </summary>
public float Length public float Length
{ {
get get
@@ -84,12 +131,18 @@ namespace TEngine
} }
} }
/// <summary>
/// 音频代理辅助器实例位置。
/// </summary>
public Vector3 Position public Vector3 Position
{ {
get => _transform.position; get => _transform.position;
set => _transform.position = value; set => _transform.position = value;
} }
/// <summary>
/// 音频代理辅助器是否循环。
/// </summary>
public bool IsLoop public bool IsLoop
{ {
get get
@@ -112,6 +165,9 @@ namespace TEngine
} }
} }
/// <summary>
/// 音频代理辅助器是否正在播放。
/// </summary>
internal bool IsPlaying internal bool IsPlaying
{ {
get get
@@ -127,11 +183,23 @@ namespace TEngine
} }
} }
/// <summary>
/// 音频代理辅助器获取当前声源。
/// </summary>
/// <returns></returns>
public AudioSource AudioResource() public AudioSource AudioResource()
{ {
return _source; return _source;
} }
/// <summary>
/// 创建音频代理辅助器。
/// </summary>
/// <param name="path">生效路径。</param>
/// <param name="bAsync">是否异步。</param>
/// <param name="audioCategory">音频轨道(类别)。</param>
/// <param name="bInPool">是否池化。</param>
/// <returns>音频代理辅助器。</returns>
public static AudioAgent Create(string path, bool bAsync, AudioCategory audioCategory, bool bInPool = false) public static AudioAgent Create(string path, bool bAsync, AudioCategory audioCategory, bool bInPool = false)
{ {
AudioAgent audioAgent = new AudioAgent(); AudioAgent audioAgent = new AudioAgent();
@@ -140,9 +208,14 @@ namespace TEngine
return audioAgent; return audioAgent;
} }
/// <summary>
/// 初始化音频代理辅助器。
/// </summary>
/// <param name="audioCategory">音频轨道(类别)。</param>
/// <param name="index">音频代理辅助器编号。</param>
public void Init(AudioCategory audioCategory,int index = 0) public void Init(AudioCategory audioCategory,int index = 0)
{ {
_audioModule = GameEntry.GetModule<AudioModule>(); _audioModule = GameModule.Audio;
GameObject host = new GameObject(Utility.Text.Format("Audio Agent Helper - {0} - {1}", audioCategory.AudioMixerGroup.name, index)); GameObject host = new GameObject(Utility.Text.Format("Audio Agent Helper - {0} - {1}", audioCategory.AudioMixerGroup.name, index));
host.transform.SetParent(audioCategory.InstanceRoot); host.transform.SetParent(audioCategory.InstanceRoot);
host.transform.localPosition = Vector3.zero; host.transform.localPosition = Vector3.zero;
@@ -151,13 +224,22 @@ namespace TEngine
_source.playOnAwake = false; _source.playOnAwake = false;
AudioMixerGroup[] audioMixerGroups = audioCategory.AudioMixer.FindMatchingGroups(Utility.Text.Format("Master/{0}/{1}", audioCategory.AudioMixerGroup.name, index)); AudioMixerGroup[] audioMixerGroups = audioCategory.AudioMixer.FindMatchingGroups(Utility.Text.Format("Master/{0}/{1}", audioCategory.AudioMixerGroup.name, index));
_source.outputAudioMixerGroup = audioMixerGroups.Length > 0 ? audioMixerGroups[0] : audioCategory.AudioMixerGroup; _source.outputAudioMixerGroup = audioMixerGroups.Length > 0 ? audioMixerGroups[0] : audioCategory.AudioMixerGroup;
_source.rolloffMode = audioCategory.AudioGroupConfig.audioRolloffMode;
_source.minDistance = audioCategory.AudioGroupConfig.minDistance;
_source.maxDistance = audioCategory.AudioGroupConfig.maxDistance;
_id = _source.GetInstanceID(); _id = _source.GetInstanceID();
} }
/// <summary>
/// 加载音频代理辅助器。
/// </summary>
/// <param name="path">资源路径。</param>
/// <param name="bAsync">是否异步。</param>
/// <param name="bInPool">是否池化。</param>
public void Load(string path, bool bAsync, bool bInPool = false) public void Load(string path, bool bAsync, bool bInPool = false)
{ {
_inPool = bInPool; _inPool = bInPool;
if (_state == State.None || _state == State.End) if (_runtimeState == RuntimeState.None || _runtimeState == RuntimeState.End)
{ {
_duration = 0; _duration = 0;
if (!string.IsNullOrEmpty(path)) if (!string.IsNullOrEmpty(path))
@@ -170,7 +252,7 @@ namespace TEngine
if (bAsync) if (bAsync)
{ {
_state = State.Loading; _runtimeState = RuntimeState.Loading;
AssetOperationHandle handle = _audioModule.ResourceManager.LoadAssetAsyncHandle<AudioClip>(path); AssetOperationHandle handle = _audioModule.ResourceManager.LoadAssetAsyncHandle<AudioClip>(path);
handle.Completed += OnAssetLoadComplete; handle.Completed += OnAssetLoadComplete;
} }
@@ -183,15 +265,19 @@ namespace TEngine
} }
else else
{ {
_pendingLoad = new LoadRequest { path = path, bAsync = bAsync }; _pendingLoad = new LoadRequest { Path = path, BAsync = bAsync };
if (_state == State.Playing) if (_runtimeState == RuntimeState.Playing)
{ {
Stop(true); Stop(true);
} }
} }
} }
/// <summary>
/// 暂停音频代理辅助器。
/// </summary>
/// <param name="fadeout">是否渐出。</param>
public void Stop(bool fadeout = false) public void Stop(bool fadeout = false)
{ {
if (_source != null) if (_source != null)
@@ -199,16 +285,20 @@ namespace TEngine
if (fadeout) if (fadeout)
{ {
_fadeoutTimer = FadeoutDuration; _fadeoutTimer = FadeoutDuration;
_state = State.FadingOut; _runtimeState = RuntimeState.FadingOut;
} }
else else
{ {
_source.Stop(); _source.Stop();
_state = State.End; _runtimeState = RuntimeState.End;
} }
} }
} }
/// <summary>
/// 资源加载完成。
/// </summary>
/// <param name="handle">资源操作句柄。</param>
void OnAssetLoadComplete(AssetOperationHandle handle) void OnAssetLoadComplete(AssetOperationHandle handle)
{ {
if (handle != null) if (handle != null)
@@ -220,7 +310,6 @@ namespace TEngine
} }
} }
if (_pendingLoad != null) if (_pendingLoad != null)
{ {
if (handle != null) if (handle != null)
@@ -228,46 +317,52 @@ namespace TEngine
handle.Dispose(); handle.Dispose();
} }
_state = State.End; _runtimeState = RuntimeState.End;
string path = _pendingLoad.path; string path = _pendingLoad.Path;
bool bAsync = _pendingLoad.bAsync; bool bAsync = _pendingLoad.BAsync;
_pendingLoad = null; _pendingLoad = null;
Load(path, bAsync); Load(path, bAsync);
} }
else if (handle != null) else if (handle != null)
{ {
if (assetOperationHandle != null) if (_assetOperationHandle != null)
{ {
assetOperationHandle.Dispose(); _assetOperationHandle.Dispose();
} }
assetOperationHandle = handle; _assetOperationHandle = handle;
_source.clip = assetOperationHandle.AssetObject as AudioClip; _source.clip = _assetOperationHandle.AssetObject as AudioClip;
if (_source.clip != null) if (_source.clip != null)
{ {
_source.Play(); _source.Play();
_state = State.Playing; _runtimeState = RuntimeState.Playing;
} }
else else
{ {
_state = State.End; _runtimeState = RuntimeState.End;
} }
} }
else else
{ {
_state = State.End; _runtimeState = RuntimeState.End;
} }
} }
/// <summary>
/// 轮询音频代理辅助器。
/// </summary>
/// <param name="delta"></param>
public void Update(float delta) public void Update(float delta)
{ {
if (_state == State.Playing) if (_runtimeState == RuntimeState.Playing)
{ {
if (!_source.isPlaying) if (!_source.isPlaying)
_state = State.End; {
_runtimeState = RuntimeState.End;
}
} }
else if (_state == State.FadingOut) else if (_runtimeState == RuntimeState.FadingOut)
{ {
if (_fadeoutTimer > 0f) if (_fadeoutTimer > 0f)
{ {
@@ -279,8 +374,8 @@ namespace TEngine
Stop(); Stop();
if (_pendingLoad != null) if (_pendingLoad != null)
{ {
string path = _pendingLoad.path; string path = _pendingLoad.Path;
bool bAsync = _pendingLoad.bAsync; bool bAsync = _pendingLoad.BAsync;
_pendingLoad = null; _pendingLoad = null;
Load(path, bAsync); Load(path, bAsync);
} }
@@ -288,10 +383,12 @@ namespace TEngine
_source.volume = _volume; _source.volume = _volume;
} }
} }
_duration += delta; _duration += delta;
} }
/// <summary>
/// 销毁音频代理辅助器。
/// </summary>
public void Destroy() public void Destroy()
{ {
if (_transform != null) if (_transform != null)
@@ -299,9 +396,9 @@ namespace TEngine
Object.Destroy(_transform.gameObject); Object.Destroy(_transform.gameObject);
} }
if (assetOperationHandle != null) if (_assetOperationHandle != null)
{ {
assetOperationHandle.Dispose(); _assetOperationHandle.Dispose();
} }
} }
} }

View File

@@ -15,13 +15,33 @@ namespace TEngine
private AudioMixer _audioMixer = null; private AudioMixer _audioMixer = null;
public List<AudioAgent> AudioAgents; public List<AudioAgent> AudioAgents;
private readonly AudioMixerGroup _audioMixerGroup; private readonly AudioMixerGroup _audioMixerGroup;
private AudioGroupConfig _audioGroupConfig;
private int _maxChannel; private int _maxChannel;
private bool _bEnable = true; private bool _bEnable = true;
/// <summary>
/// 音频混响器。
/// </summary>
public AudioMixer AudioMixer => _audioMixer; public AudioMixer AudioMixer => _audioMixer;
/// <summary>
/// 音频混响器组。
/// </summary>
public AudioMixerGroup AudioMixerGroup => _audioMixerGroup; public AudioMixerGroup AudioMixerGroup => _audioMixerGroup;
/// <summary>
/// 音频组配置。
/// </summary>
public AudioGroupConfig AudioGroupConfig => _audioGroupConfig;
/// <summary>
/// 实例化根节点。
/// </summary>
public Transform InstanceRoot { private set; get; } public Transform InstanceRoot { private set; get; }
/// <summary>
/// 音频轨道是否启用。
/// </summary>
public bool Enable public bool Enable
{ {
get => _bEnable; get => _bEnable;
@@ -44,12 +64,18 @@ namespace TEngine
} }
} }
/// <summary>
public AudioCategory(int maxChannel, AudioMixer audioMixer,AudioType audioType) /// 音频轨道构造函数。
/// </summary>
/// <param name="maxChannel">最大Channel。</param>
/// <param name="audioMixer">音频混响器。</param>
/// <param name="audioGroupConfig">音频轨道组配置。</param>
public AudioCategory(int maxChannel, AudioMixer audioMixer,AudioGroupConfig audioGroupConfig)
{ {
_audioMixer = audioMixer; _audioMixer = audioMixer;
_maxChannel = maxChannel; _maxChannel = maxChannel;
AudioMixerGroup[] audioMixerGroups = audioMixer.FindMatchingGroups(Utility.Text.Format("Master/{0}", audioType.ToString())); _audioGroupConfig = audioGroupConfig;
AudioMixerGroup[] audioMixerGroups = audioMixer.FindMatchingGroups(Utility.Text.Format("Master/{0}", audioGroupConfig.AudioType.ToString()));
if (audioMixerGroups.Length > 0) if (audioMixerGroups.Length > 0)
{ {
_audioMixerGroup = audioMixerGroups[0]; _audioMixerGroup = audioMixerGroups[0];
@@ -69,6 +95,10 @@ namespace TEngine
} }
} }
/// <summary>
/// 增加音频。
/// </summary>
/// <param name="num"></param>
public void AddAudio(int num) public void AddAudio(int num)
{ {
_maxChannel += num; _maxChannel += num;
@@ -78,7 +108,13 @@ namespace TEngine
} }
} }
/// <summary>
/// 播放音频。
/// </summary>
/// <param name="path"></param>
/// <param name="bAsync"></param>
/// <param name="bInPool"></param>
/// <returns></returns>
public AudioAgent Play(string path, bool bAsync, bool bInPool = false) public AudioAgent Play(string path, bool bAsync, bool bInPool = false)
{ {
if (!_bEnable) if (!_bEnable)
@@ -91,7 +127,7 @@ namespace TEngine
for (int i = 0; i < AudioAgents.Count; i++) for (int i = 0; i < AudioAgents.Count; i++)
{ {
if (AudioAgents[i].assetOperationHandle == null || AudioAgents[i].IsFinish) if (AudioAgents[i].assetOperationHandle == null || AudioAgents[i].IsFree)
{ {
freeChannel = i; freeChannel = i;
break; break;
@@ -123,6 +159,10 @@ namespace TEngine
} }
} }
/// <summary>
/// 暂停音频。
/// </summary>
/// <param name="fadeout">是否渐出</param>
public void Stop(bool fadeout) public void Stop(bool fadeout)
{ {
for (int i = 0; i < AudioAgents.Count; ++i) for (int i = 0; i < AudioAgents.Count; ++i)
@@ -134,6 +174,10 @@ namespace TEngine
} }
} }
/// <summary>
/// 音频轨道轮询。
/// </summary>
/// <param name="delta"></param>
public void Update(float delta) public void Update(float delta)
{ {
for (int i = 0; i < AudioAgents.Count; ++i) for (int i = 0; i < AudioAgents.Count; ++i)

View File

@@ -3,6 +3,9 @@ using UnityEngine;
namespace TEngine namespace TEngine
{ {
/// <summary>
/// 音频轨道组配置。
/// </summary>
[Serializable] [Serializable]
public sealed class AudioGroupConfig public sealed class AudioGroupConfig
{ {
@@ -20,6 +23,12 @@ namespace TEngine
public AudioType AudioType; public AudioType AudioType;
public AudioRolloffMode audioRolloffMode = AudioRolloffMode.Logarithmic;
public float minDistance = 1f;
public float maxDistance = 500f;
public string Name public string Name
{ {
get get

View File

@@ -23,15 +23,10 @@ namespace TEngine
private float _volume = 1f; private float _volume = 1f;
private bool _enable = true; private bool _enable = true;
private int _audioChannelMaxNum = 0;
private AudioCategory[] _audioCategories = new AudioCategory[(int)AudioType.Max]; private AudioCategory[] _audioCategories = new AudioCategory[(int)AudioType.Max];
private readonly float[] _categoriesVolume = new float[(int)AudioType.Max]; private readonly float[] _categoriesVolume = new float[(int)AudioType.Max];
public readonly Dictionary<string, AssetOperationHandle> AudioClipPool = new Dictionary<string, AssetOperationHandle>(); public readonly Dictionary<string, AssetOperationHandle> AudioClipPool = new Dictionary<string, AssetOperationHandle>();
public IResourceManager ResourceManager; public IResourceManager ResourceManager;
/// <summary>
/// Unity是否禁用音频模块。
/// </summary>
private bool _bUnityAudioDisabled = false; private bool _bUnityAudioDisabled = false;
#region Public Propreties #region Public Propreties
@@ -374,7 +369,7 @@ namespace TEngine
{ {
AudioType audioType = (AudioType)index; AudioType audioType = (AudioType)index;
AudioGroupConfig audioGroupConfig = m_AudioGroupConfigs.First(t => t.AudioType == audioType); AudioGroupConfig audioGroupConfig = m_AudioGroupConfigs.First(t => t.AudioType == audioType);
_audioCategories[index] = new AudioCategory(audioGroupConfig.AgentHelperCount, m_AudioMixer, audioType); _audioCategories[index] = new AudioCategory(audioGroupConfig.AgentHelperCount, m_AudioMixer, audioGroupConfig);
_categoriesVolume[index] = audioGroupConfig.Volume; _categoriesVolume[index] = audioGroupConfig.Volume;
} }
} }
@@ -474,34 +469,6 @@ namespace TEngine
} }
} }
/// <summary>
/// 修改最大的音效播放上限,
/// </summary>
/// <param name="num"></param> 最大播放数量
public void ChangeAudioChannelMaxNum(int num)
{
if (_bUnityAudioDisabled)
{
return;
}
if (num >= _audioChannelMaxNum)
{
_audioCategories[(int)AudioType.Sound].AddAudio(num - _audioChannelMaxNum);
_audioChannelMaxNum = num;
}
else
{
Stop(AudioType.Sound, true);
_audioChannelMaxNum = num;
_audioCategories[(int)AudioType.Sound].Enable = false;
_audioCategories[(int)AudioType.Sound] = new AudioCategory(_audioChannelMaxNum, m_AudioMixer, AudioType.Sound);
_categoriesVolume[(int)AudioType.Sound] = 1.0f;
}
}
/// <summary> /// <summary>
/// 预先加载AudioClip并放入对象池。 /// 预先加载AudioClip并放入对象池。
/// </summary> /// </summary>
@@ -562,6 +529,9 @@ namespace TEngine
AudioClipPool.Clear(); AudioClipPool.Clear();
} }
/// <summary>
/// 音频模块轮询。
/// </summary>
private void Update() private void Update()
{ {
for (int i = 0; i < _audioCategories.Length; ++i) for (int i = 0; i < _audioCategories.Length; ++i)