NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Framework/Audio/AudioCriwareMgr.cs

1572 lines
45 KiB
C#
Raw Normal View History

using PhxhSDK;
using System;
using Framework;
using System.Collections.Generic;
2023-12-13 15:14:52 +08:00
using cfg.AudioCfg;
using CriWare;
using CriWare.Assets;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.SceneManagement;
using Object = UnityEngine.Object;
using Constants = Framework.Constants;
public class AudioCriwareManager : Singlenton<AudioCriwareManager>, IStart, IInitable, IUpdatable, IAudioPlay
{
public GameObject initGameObject;
public ClipType curClipType;
protected float vol = 1f;
protected float musicVol = 1f;
protected float soundsVol = 1f;
2024-04-28 14:24:10 +08:00
protected float speakVol = 1f;
protected Dictionary<int, Audio> musicAudio;
protected Dictionary<int, Audio> soundsAudio;
protected Dictionary<string, int> loadingAcb;
2024-04-11 19:02:11 +08:00
private List<GameObject> _rootGoList;
private Dictionary<GameObject, Audio> _audioDic;
/// <summary>
/// 背景音乐播放器
/// </summary>
2024-04-11 19:02:11 +08:00
private Audio _bgmAudio;
2024-07-15 17:07:49 +08:00
public Audio BgmAudio
{
get { return _bgmAudio; }
}
2024-04-11 19:02:11 +08:00
protected static int SOUNDS_POOL_MAX_NUM = 25;
protected static int MUSIC_POOL_MAX_NUM = 5;
protected bool banMusic = false;
protected bool banSound = false;
protected bool initialized = false;
protected List<int> _toBeRemoved = new List<int>();
2023-12-13 15:14:52 +08:00
private bool _isOpenSpeakVoice = true;
private GameObject _criError;
private GameObject _criAtomGo;
private static Queue<Audio> _freeMusicAudio;
private static Queue<Audio> _freeSoundsAudio;
2024-04-11 19:02:11 +08:00
private Audio _oldestSound;
2023-11-30 15:56:15 +08:00
private Dictionary<string, bool> _isAcbLoadedDic = new Dictionary<string, bool>();
private Dictionary<string, CriAtomAcbAsset> _LoadedAcbAssetDic = new Dictionary<string, CriAtomAcbAsset>();
2024-01-19 17:25:06 +08:00
private CriAtomListener _listener;
public CriAtomExOutputAnalyzer analyzer=null;
public bool IsAnalyzer = false;
2024-04-11 19:02:11 +08:00
private string _musicAssetPath = "Assets/Audio/Music/NLD_BGM";
private string _soundAssetPath = "Assets/Audio/Music/CueSheet_ProjNLD";
2024-06-12 13:51:49 +08:00
private string _speakAssetPath = "Assets/Audio/Music/CueSheet_VOICE";
2024-07-04 18:06:32 +08:00
private string _assetPath0 = "Assets/Audio/Music/CueSheet_SE";
public void Start()
{
if (initGameObject == null)
{
// Need to create a new GameObject to attach the singleton to.
curClipType = ClipType.CriwareClip;
initGameObject = new GameObject();
initGameObject.name = "AudioOld(Singleton)";
//initGameObject.hideFlags = HideFlags.HideInHierarchy;
// Make instance persistent.
Object.DontDestroyOnLoad(initGameObject);
//Object.DontDestroyOnLoad(GameObject.Find("CriWareLibraryInitializer"));
//#if UNITY_EDITOR
// if (curClipType == ClipType.CriwareClip)
// {
// _criError = new GameObject();
// _criError.name = "CriwareError";
// _criError.AddComponent<CriWareErrorHandler>();
// Object.DontDestroyOnLoad(_criError);
// }
2024-04-11 19:02:11 +08:00
_rootGoList = new List<GameObject>();
_audioDic = new Dictionary<GameObject, Audio>();
for (int i = 0; i < MUSIC_POOL_MAX_NUM + SOUNDS_POOL_MAX_NUM; i++)
{
var go = new GameObject();
go.name = "Audio";
go.transform.SetParent(initGameObject.transform);
_rootGoList.Add(go);
}
_PreLoadAssets();
//#endif
}
}
2024-04-11 19:02:11 +08:00
private async void _PreLoadAssets()
{
2024-04-28 16:36:43 +08:00
if (AudioManager.DisableAudio) return;
2024-04-11 19:02:11 +08:00
await LoadAudioAsync(AudioType.MUSIC, _musicAssetPath);
await LoadAudioAsync(AudioType.SOUND, _soundAssetPath);
2024-06-12 13:51:49 +08:00
await LoadAudioAsync(AudioType.SOUND, _speakAssetPath);
2024-07-04 18:06:32 +08:00
await LoadAudioAsync(AudioType.SOUND, _assetPath0);
2024-04-11 19:02:11 +08:00
}
#region 公共属性
/// <summary>
/// When set to true, new Audios that have the same audio clip as any other Audio, will be ignored
/// </summary>
public bool IgnoreDuplicateMusic { get; set; }
/// <summary>
/// When set to true, new Audios that have the same audio clip as any other Audio, will be ignored
/// </summary>
public bool IgnoreDuplicateSounds { get; set; }
public float GlobalVolume
{
get { return vol; }
set { vol = value; }
}
public float GlobalMusicVolume
{
get { return musicVol; }
set { musicVol = value; }
}
public float GlobalSoundsVolume
{
get { return soundsVol; }
set { soundsVol = value; }
}
2023-12-13 15:14:52 +08:00
public bool GlobalIsOpenSpeak
{
get { return _isOpenSpeakVoice; }
set { _isOpenSpeakVoice = value; }
}
2024-04-28 14:24:10 +08:00
public float GlobalSpeakVolume
{
get { return speakVol; }
set { speakVol = value; }
}
public void Init()
{
if (!initialized)
{
musicAudio = new Dictionary<int, Audio>();
soundsAudio = new Dictionary<int, Audio>();
loadingAcb = new Dictionary<string, int>();
_freeMusicAudio = new Queue<Audio>();
_freeSoundsAudio = new Queue<Audio>();
IgnoreDuplicateMusic = false;
IgnoreDuplicateSounds = false;
initialized = true;
}
2024-04-11 19:02:11 +08:00
//SceneManager.sceneLoaded += OnSceneLoaded;
}
2024-04-11 19:02:11 +08:00
#endregion
2024-04-11 19:02:11 +08:00
#region 公共方法
public void Release()
{
2024-04-11 19:02:11 +08:00
//SceneManager.sceneLoaded -= OnSceneLoaded;
2023-11-30 15:56:15 +08:00
_LoadedAcbAssetDic.Clear();
_isAcbLoadedDic.Clear();
}
public void RemoveAudio(GameObject go)
{
2023-11-30 15:56:15 +08:00
try
{
2023-11-30 15:56:15 +08:00
var source = go.GetComponent<CriAtomSourceForAsset>();
if (source)
{
2023-11-30 15:56:15 +08:00
using var e = soundsAudio.GetEnumerator();
while (e.MoveNext())
{
2023-11-30 15:56:15 +08:00
var audio = e.Current.Value;
if (audio.audioSource == source)
{
audio.Stop();
_toBeRemoved.Add(e.Current.Key);
}
}
}
}
2023-11-30 15:56:15 +08:00
catch (Exception e)
{
DebugUtil.LogError($"RemoveAudio, {e}");
throw;
}
}
public void PauseAll()
{
PauseAllMusic();
PauseAllSounds();
}
public void PauseAllMusic()
{
List<int> keys = new List<int>(musicAudio.Keys);
foreach (int key in keys)
{
Audio audio = musicAudio[key];
audio.Pause();
}
}
public void PauseAllSounds()
{
List<int> keys = new List<int>(soundsAudio.Keys);
foreach (int key in keys)
{
Audio audio = soundsAudio[key];
audio.Pause();
}
}
public void ResumeAll()
{
ResumeAllMusic();
ResumeAllSounds();
}
public void ResumeAllMusic()
{
if (banMusic)
return;
List<int> keys = new List<int>(musicAudio.Keys);
foreach (int key in keys)
{
2024-07-09 14:02:15 +08:00
DebugUtil.Log("audio status: " + musicAudio[key].audioSource.status);
Audio audio = musicAudio[key];
audio.Resume();
}
}
public void ResumeAllSounds()
{
List<int> keys = new List<int>(soundsAudio.Keys);
foreach (int key in keys)
{
Audio audio = soundsAudio[key];
audio.Resume();
}
}
public void StopAll(float fadeOutSeconds = -1.0f)
{
StopAllMusic(fadeOutSeconds);
StopAllSounds();
}
public void StopAllMusic(float fadeOutSeconds = -1.0f)
{
List<int> keys = new List<int>(musicAudio.Keys);
foreach (int key in keys)
{
Audio audio = musicAudio[key];
if (fadeOutSeconds > 0)
{
audio.fadeOutSeconds = fadeOutSeconds;
}
audio.Stop();
}
}
public void StopAllSounds()
{
List<int> keys = new List<int>(soundsAudio.Keys);
foreach (int key in keys)
{
Audio audio = soundsAudio[key];
audio.Stop();
}
}
2024-07-08 17:02:56 +08:00
public void StopBGM()
{
_bgmAudio.Stop();
}
public void StopSoundById(int soundId)
{
if (soundId >= 0)
{
List<int> keys = new List<int>(soundsAudio.Keys);
foreach (int key in keys)
{
Audio audio = soundsAudio[key];
if (audio.audioID == soundId)
{
audio.Stop();
}
}
}
}
public void StopMusicById(int soundId)
{
if (soundId >= 0)
{
List<int> keys = new List<int>(musicAudio.Keys);
foreach (int key in keys)
{
Audio audio = musicAudio[key];
if (audio.audioID == soundId)
{
audio.Stop();
}
}
}
}
2024-04-23 19:42:31 +08:00
public Audio GetAudioByID(AudioType audioType, int id)
{
if (audioType == AudioType.MUSIC)
{
if (!musicAudio.ContainsKey(id))
{
return null;
}
return musicAudio[id];
}
if (audioType == AudioType.SOUND)
{
if (!soundsAudio.ContainsKey(id))
{
return null;
}
return soundsAudio[id];
}
return null;
}
2024-04-11 19:02:11 +08:00
#endregion
#region 播放逻辑
/// <summary>
/// 获取播放器挂载节点
/// </summary>
private GameObject _GetRootGo(GameObject posObj = null, bool isSound = false)
{
if (!isSound)
{
if (_bgmAudio == null)
{
return _rootGoList[0];
}
return _bgmAudio.RootGo;
}
if (posObj != null)
{
foreach (var kv in _audioDic)
{
var go = kv.Key;
var audio = kv.Value;
if (audio.PosGo == posObj && _bgmAudio != audio)
{
return go;
}
}
}
for (int i = 0; i < _rootGoList.Count; i++)
{
var go = _rootGoList[i];
if (!IsAudioExist(go))
{
return go;
}
}
foreach (var kv in _audioDic)
{
var go = kv.Key;
var audio = kv.Value;
if (audio.IsStopped && _bgmAudio != audio)
{
return go;
}
}
2024-04-11 19:02:11 +08:00
if (isSound)
{
var minID = SOUNDS_POOL_MAX_NUM + MUSIC_POOL_MAX_NUM + 1;
foreach (var kv in soundsAudio)
{
var curAudio = kv.Value;
if (minID == Math.Min(minID, curAudio.PlayID))
{
continue;
}
minID = curAudio.PlayID;
_oldestSound = curAudio;
}
return _oldestSound.RootGo;
}
return null;
}
private bool IsAudioExist(GameObject rootGo)
{
if (_audioDic.ContainsKey(rootGo))
{
return true;
}
return false;
}
public async UniTask<int> PlayMusicCommon(string musicName, string cueName = "", bool loop = true)
{
2023-11-30 15:56:15 +08:00
try
{
2023-11-30 15:56:15 +08:00
CriAtomAcbAsset au;
if (!_isAcbLoadedDic.ContainsKey(musicName))
{
await CheckIsLoading(musicName);
}
//if (AssetManager.Instance.IsAssetPreLoaded(musicName + ".acb"))
if (_isAcbLoadedDic.ContainsKey(musicName))
{
au = LoadAudio(AudioType.MUSIC, musicName);
}
else
{
au = await LoadAudioAsync(AudioType.MUSIC, musicName);
}
2023-11-30 15:56:15 +08:00
if (au != null)
{
2024-06-12 13:51:49 +08:00
AudioInfo audioInfo = new AudioInfo()
2023-11-30 15:56:15 +08:00
{
persist = true,
volume = 1,
fadeInValue = 0.3f,
fadeOutValue = 0.3f,
};
return PlayMusic(au, loop, null, false, cueName, audioInfo);
}
2023-11-30 15:56:15 +08:00
return -1;
}
catch (Exception e)
{
DebugUtil.LogError($"playMusicCommon, {cueName}, {e}");
throw;
}
}
2024-04-11 19:02:11 +08:00
// public void Update(float deltaTime)
// {
// using (var e = musicAudio.GetEnumerator())
// {
// while (e.MoveNext())
// {
// var music = e.Current.Value;
// music.Update();
// if (!music.audioSource)
// {
// _toBeRemoved.Add(e.Current.Key);
// }
// if (!music.IsPlaying && !music.IsPaused && !music.IsLoading)
// {
// _toBeRemoved.Add(e.Current.Key);
// }
// }
//
// if (_toBeRemoved.Count > 0)
// {
// for (int i = 0; i < _toBeRemoved.Count; i++)
// {
// var audio = musicAudio[_toBeRemoved[i]];
// if (!GetIsArrivePoolLimit(AudioType.MUSIC))
// {
// _freeMusicAudio.Enqueue(audio);
// }
// else
// {
// switch (curClipType)
// {
// case ClipType.AudioClip:
// {
// Object.Destroy(audio.audioSource);
// break;
// }
// case ClipType.CriwareClip:
// {
// if (audio.RootGo && audio.RootGo != initGameObject)
// {
// Object.Destroy(audio.RootGo);
// }
// Object.Destroy(audio.audioSource);
// break;
// }
// default:
// break;
// }
// }
//
// musicAudio.Remove(_toBeRemoved[i]);
// }
//
// _toBeRemoved.Clear();
// }
// }
//
//
// using (var e1 = soundsAudio.GetEnumerator())
// {
// // Update sound fx
// while (e1.MoveNext())
// {
// var sound = e1.Current.Value;
// sound.Update();
// if (!sound.audioSource)
// {
// _toBeRemoved.Add(e1.Current.Key);
// }
// else if (!sound.IsPlaying && !sound.IsPaused && !sound.IsLoading)
// {
// _toBeRemoved.Add(e1.Current.Key);
// }
// }
//
// if (_toBeRemoved.Count > 0)
// {
// for (int i = 0; i < _toBeRemoved.Count; i++)
// {
// var audio = soundsAudio[_toBeRemoved[i]];
//
// if (!GetIsArrivePoolLimit(AudioType.SOUND))
// {
// _freeSoundsAudio.Enqueue(audio);
// }
// else
// {
// switch (curClipType)
// {
// case ClipType.AudioClip:
// {
// Object.Destroy(audio.audioSource);
// break;
// }
// case ClipType.CriwareClip:
// {
// Object.Destroy(audio.audioSource);
//
// if (audio.RootGo && audio.RootGo != initGameObject)
// {
// Object.Destroy(audio.RootGo);
// }
// break;
// }
// default:
// break;
// }
// }
//
// soundsAudio.Remove(_toBeRemoved[i]);
// }
//
// _toBeRemoved.Clear();
// }
// }
//
// }
public void Update(float dt)
{
2024-04-11 19:02:11 +08:00
// foreach (var kv in musicAudio)
// {
// var audio = kv.Value;
// if (!audio.IsStopped)
// {
// audio.Update();
// _UpdateObjPos(audio);
// }
// else
// {
// audio.PosGo = null;
// }
// }
if (_bgmAudio != null)
{
2024-04-11 19:02:11 +08:00
if (!_bgmAudio.IsStopped)
{
2024-04-11 19:02:11 +08:00
_bgmAudio.Update();
}
2024-04-11 19:02:11 +08:00
else
{
2024-04-11 19:02:11 +08:00
_bgmAudio.PosGo = null;
}
}
2024-07-09 14:02:15 +08:00
//if (_albumAudio != null)
//{
// if(!_albumAudio.IsStopped)
// {
// _albumAudio.Update();
// }
// else
// {
// _albumAudio.PosGo = null;
// }
//}
2024-04-11 19:02:11 +08:00
foreach (var kv in soundsAudio)
{
2024-04-11 19:02:11 +08:00
var audio = kv.Value;
if (!audio.IsStopped)
{
2024-04-11 19:02:11 +08:00
audio.Update();
_UpdateObjPos(audio);
}
2024-04-11 19:02:11 +08:00
else
{
2024-04-11 19:02:11 +08:00
audio.PosGo = null;
}
}
}
2024-04-11 19:02:11 +08:00
private void _UpdateObjPos(Audio audio)
{
var rootGo = audio.RootGo;
var posGo = audio.PosGo;
if (posGo)
{
if (rootGo != posGo)
{
rootGo.transform.position = posGo.transform.position;
}
}
}
2024-01-19 17:25:06 +08:00
public void AfterSwitchMainCamera(Camera camera)
{
var listener = camera.GetComponent<CriAtomListener>();
if (!listener)
{
camera.gameObject.AddComponent<CriAtomListener>();
}
}
private bool GetIsArrivePoolLimit(AudioType audioType)
{
if (audioType == AudioType.MUSIC)
{
return musicAudio.Count + _freeMusicAudio.Count >= MUSIC_POOL_MAX_NUM;
}
return soundsAudio.Count + _freeSoundsAudio.Count >= SOUNDS_POOL_MAX_NUM;
}
2024-04-28 14:24:10 +08:00
public async UniTask<int> PlaySoundCommon(string soundName, string cueName = "", bool isSpeak = false)
{
2023-11-30 15:56:15 +08:00
if (!_isAcbLoadedDic.ContainsKey(soundName))
{
await CheckIsLoading(soundName);
}
if (GlobalSoundsVolume <= 0.01 && !isSpeak)
{
return -1;
}
if (GlobalSpeakVolume <= 0.01 && isSpeak)
{
return -1;
}
try
{
switch (curClipType)
{
case ClipType.AudioClip:
{
break;
}
case ClipType.CriwareClip:
{
CriAtomAcbAsset acb;
2023-11-30 15:56:15 +08:00
//if (AssetManager.Instance.IsAssetPreLoaded(soundName + ".acb"))
if (_isAcbLoadedDic.ContainsKey(soundName))
{
acb = LoadAudio(AudioType.SOUND, soundName);
}
else
{
acb = await LoadAudioAsync(AudioType.SOUND, soundName);
}
if (acb != null)
{
2024-04-28 14:24:10 +08:00
return PlaySound(acb, GlobalVolume, false, null, isSpeak, false, cueName);
}
break;
}
default:
break;
}
DebugUtil.LogError("==== audio null!!! ====");
}
catch (Exception e)
{
DebugUtil.LogError("{0}.PlaySound:{1} error:{2}", GetType(), soundName, e.Message);
}
return -1;
}
public void SetMusicEnable(bool isEnable)
{
GlobalMusicVolume = isEnable ? 1 : 0;
}
public void SetSoundEnable(bool isEnable)
{
GlobalSoundsVolume = isEnable ? 1 : 0;
}
2024-04-11 19:02:11 +08:00
public async UniTask<int> PlayMusicCommon(string musicName, GameObject posObj, string cueName = "", bool loop = true)
{
2023-11-30 15:56:15 +08:00
try
{
2023-11-30 15:56:15 +08:00
CriAtomAcbAsset au;
if (!_isAcbLoadedDic.ContainsKey(musicName))
{
await CheckIsLoading(musicName);
}
//if (AssetManager.Instance.IsAssetPreLoaded(musicName + ".acb"))
if (!_isAcbLoadedDic.ContainsKey(musicName))
{
au = await LoadAudioAsync(AudioType.MUSIC, musicName);
}
else
{
au = LoadAudio(AudioType.MUSIC, musicName);
}
2023-11-30 15:56:15 +08:00
if (au != null)
{
2024-06-12 13:51:49 +08:00
AudioInfo audioInfo = new AudioInfo()
2023-11-30 15:56:15 +08:00
{
persist = true,
volume = 1,
fadeInValue = 0.3f,
fadeOutValue = 0.3f,
};
2024-04-11 19:02:11 +08:00
return PlayMusic(au, loop, posObj, true, cueName, audioInfo);
2023-11-30 15:56:15 +08:00
}
2023-11-30 15:56:15 +08:00
return -1;
}
catch (Exception e)
{
DebugUtil.LogError($"PlayMusicCommon, cueName = {cueName}, {e}");
throw;
}
}
2024-04-28 14:24:10 +08:00
public async UniTask<int> PlaySoundCommon(string soundName, GameObject posObj, string cueName, bool is3D = false,
Vector3 pos = new Vector3(), bool isSpeak = false)
{
2023-11-30 15:56:15 +08:00
if (!_isAcbLoadedDic.ContainsKey(soundName))
{
await CheckIsLoading(soundName);
}
if (GlobalSoundsVolume <= 0.01 && !isSpeak)
{
return -1;
}
if (GlobalSpeakVolume <= 0.01 && isSpeak)
{
return -1;
}
try
{
switch (curClipType)
{
case ClipType.AudioClip:
{
break;
}
case ClipType.CriwareClip:
{
CriAtomAcbAsset acb;
2023-11-30 15:56:15 +08:00
//if (AssetManager.Instance.IsAssetPreLoaded(soundName + ".acb"))
if (_isAcbLoadedDic.ContainsKey(soundName))
{
acb = LoadAudio(AudioType.SOUND, soundName);
}
else
{
acb = await LoadAudioAsync(AudioType.SOUND, soundName);
}
if (acb != null)
{
2024-04-28 14:24:10 +08:00
return PlaySound(acb, GlobalVolume, false, posObj, isSpeak, is3D, cueName, pos);
}
break;
}
default:
break;
}
DebugUtil.LogError("==== audio null!!! ====");
}
catch (Exception e)
{
DebugUtil.LogError("{0}.PlaySound:{1} error:{2}", GetType(), soundName, e.Message);
}
return -1;
}
2024-07-15 17:07:49 +08:00
private async UniTask CheckIsLoading(string audioName)
{
while (loadingAcb.ContainsKey(audioName))
{
await UniTask.NextFrame();
}
}
2024-04-28 14:24:10 +08:00
private int PlaySoundCommonImmediately(string soundName, GameObject posObj, string cueName, bool is3D = false,
Vector3 pos = new Vector3(), bool isSpeak = false)
2023-11-30 15:56:15 +08:00
{
if (!_isAcbLoadedDic.ContainsKey(soundName))
{
DebugUtil.LogError($"--- acb资源没有完成加载请检查 acbName: {soundName} ---");
return -1;
}
if (GlobalSoundsVolume <= 0.01 && !isSpeak)
{
return -1;
}
if (GlobalSpeakVolume <= 0.01 && isSpeak)
{
return -1;
}
2023-11-30 15:56:15 +08:00
try
{
var acb = LoadAudio(AudioType.SOUND, soundName);
2024-04-28 14:24:10 +08:00
return PlaySound(acb, GlobalVolume, false, posObj, isSpeak, is3D, cueName, pos);
2023-11-30 15:56:15 +08:00
}
catch (Exception e)
{
DebugUtil.LogError(e);
throw;
}
}
2024-04-28 14:24:10 +08:00
private int PlaySoundCommonImmediately(string soundName, string cueName, bool isSpeak = false)
2023-11-30 15:56:15 +08:00
{
if (!_isAcbLoadedDic.ContainsKey(soundName))
{
DebugUtil.LogError($"--- acb资源没有完成加载请检查 acbName: {soundName} ---");
return -1;
}
if (GlobalSoundsVolume <= 0.01 && !isSpeak)
{
return -1;
}
if (GlobalSpeakVolume <= 0.01 && isSpeak)
{
return -1;
}
2023-11-30 15:56:15 +08:00
try
{
var acb = LoadAudio(AudioType.SOUND, soundName);
2024-04-28 14:24:10 +08:00
return PlaySound(acb, GlobalVolume, false, null, isSpeak, false, cueName);
2023-11-30 15:56:15 +08:00
}
catch (Exception e)
{
DebugUtil.LogError(e);
throw;
}
}
/// <summary>
/// 播放音乐
/// </summary>
/// <param name="acbAsset"></param> acbAsset
/// <param name="loop"></param> 是否循环
/// <param name="sourceTransform"></param> 挂载的trans
/// <param name="is3D"></param> 是否3D音效
/// <param name="cueName"></param> 播放的Cue里面哪个音源
/// <param name="audioInfo"></param> 结构体,包含淡入淡出的时间
/// <returns></returns>
2024-07-03 12:05:52 +08:00
private int PlayMusic(CriAtomAcbAsset acbAsset, bool loop, GameObject posGo,
2024-06-12 13:51:49 +08:00
bool is3D, string cueName, AudioInfo audioInfo)
{
if (acbAsset == null)
{
DebugUtil.LogError("Sound Manager: Audio clip is null, cannot play music", acbAsset);
}
2023-11-30 15:56:15 +08:00
try
{
2023-11-30 15:56:15 +08:00
if (IgnoreDuplicateMusic)
{
2023-11-30 15:56:15 +08:00
List<int> keys = new List<int>(musicAudio.Keys);
foreach (int key in keys)
{
2023-11-30 15:56:15 +08:00
if (musicAudio[key].audioSource.Cue.AcbAsset.name == acbAsset.name)
{
return musicAudio[key].audioID;
}
}
}
2024-07-03 12:05:52 +08:00
2023-11-30 15:56:15 +08:00
// Stop all current music playing
//StopAllMusic(audioInfo.fadeOutValue);
2024-07-03 12:05:52 +08:00
2023-11-30 15:56:15 +08:00
// Create the audioSource
Audio audio;
2024-04-11 19:02:11 +08:00
GameObject rootGo;
if (_bgmAudio == null)
2023-11-30 15:56:15 +08:00
{
2024-04-11 19:02:11 +08:00
rootGo = _GetRootGo(posGo);
2023-11-30 15:56:15 +08:00
}
else
{
2024-04-11 19:02:11 +08:00
rootGo = _bgmAudio.RootGo;
2023-11-30 15:56:15 +08:00
}
2024-04-11 19:02:11 +08:00
if (!posGo)
{
posGo = initGameObject;
}
2024-07-03 12:05:52 +08:00
2024-04-11 19:02:11 +08:00
if (_bgmAudio != null)
{
//audio = _bgmAudio;
2024-07-08 15:28:18 +08:00
_bgmAudio.Stop();
2024-07-15 17:07:49 +08:00
_bgmAudio.SetAcbAsset(acbAsset);//设置音频资源
2024-04-28 14:24:10 +08:00
_bgmAudio.audioType = AudioBase.AudioType.Music;
_bgmAudio.SetVolume(audioInfo.volume);
2024-04-11 19:02:11 +08:00
_bgmAudio.Play(cueName, true);
}
else//创建新的背景音乐播放器,此时构造函数中将检查频谱分析器的绑定
2024-04-11 19:02:11 +08:00
{
rootGo.transform.SetParent(initGameObject.transform);
audio = new Audio(Audio.AudioType.Music, acbAsset, loop, posGo, rootGo, is3D, cueName, audioInfo);
rootGo.name = "Music" + audio.audioID;
_audioDic.TryAdd(rootGo, audio);
_bgmAudio = audio;
2024-04-11 19:02:11 +08:00
}
rootGo.transform.position = posGo.transform.position;
2024-07-03 12:05:52 +08:00
2023-11-30 15:56:15 +08:00
// Add it to music list
2024-04-11 19:02:11 +08:00
musicAudio.TryAdd(_bgmAudio.audioID, _bgmAudio);
2024-07-03 12:05:52 +08:00
2023-11-30 15:56:15 +08:00
if (banMusic)
{
2024-04-11 19:02:11 +08:00
_bgmAudio.Pause();
2023-11-30 15:56:15 +08:00
}
2024-07-03 12:05:52 +08:00
2024-04-11 19:02:11 +08:00
return _bgmAudio.audioID;
2023-11-30 15:56:15 +08:00
}
catch (Exception e)
{
2023-11-30 15:56:15 +08:00
DebugUtil.LogError(e);
throw;
}
2024-07-15 17:07:49 +08:00
}
2024-04-11 19:02:11 +08:00
private int PlaySound(CriAtomAcbAsset acbAsset, float volume, bool loop, GameObject posGo,
2024-04-28 14:24:10 +08:00
bool isSpeak = false, bool is3D = false, string cueName = "", Vector3 pos = new Vector3(), float pitch = 1.0f)
{
if (acbAsset == null)
{
DebugUtil.LogError("Sound Manager: Audio clip is null, cannot play music");
}
2023-11-30 15:56:15 +08:00
try
{
2023-11-30 15:56:15 +08:00
if (banSound)
{
return -1;
}
2024-04-11 19:02:11 +08:00
// if (IgnoreDuplicateSounds)
// {
// List<int> keys = new List<int>(soundsAudio.Keys);
// foreach (var key in keys)
// {
// if (soundsAudio.ContainsKey(key) && soundsAudio[key].audioSource.Cue.AcbAsset.name.Equals(acbAsset.name) )
// return soundsAudio[key].audioID;
// }
// }
#if UNITY_EDITOR || UNITY_IOS || UNITY_ANDROID
2023-11-30 15:56:15 +08:00
// Create the audioSource
Audio audio;
2024-06-12 13:51:49 +08:00
AudioInfo audioInfo = new AudioInfo()
2023-11-30 15:56:15 +08:00
{
persist = false,
volume = volume,
fadeInValue = 0f,
fadeOutValue = 0f,
2024-04-28 14:24:10 +08:00
isSpeak = isSpeak
2023-11-30 15:56:15 +08:00
};
2024-04-11 19:02:11 +08:00
GameObject rootGo = _GetRootGo(posGo, true);
if (!posGo)
2023-11-30 15:56:15 +08:00
{
2024-04-11 19:02:11 +08:00
rootGo.transform.position = pos;
posGo = rootGo;
2023-11-30 15:56:15 +08:00
}
else
{
2024-04-11 19:02:11 +08:00
rootGo.transform.position = posGo.transform.position;
2023-11-30 15:56:15 +08:00
}
2024-04-11 19:02:11 +08:00
if (IsAudioExist(rootGo))
{
2024-04-11 19:02:11 +08:00
audio = _audioDic[rootGo];
audio.SetAcbAsset(acbAsset);
2024-04-28 14:24:10 +08:00
audio.audioType = AudioBase.AudioType.Sound;
2024-04-11 19:02:11 +08:00
audio.SetIs3D(is3D);
2024-04-28 14:24:10 +08:00
audio.SetVolume(audioInfo.volume);
audio.SetIsSpeak(isSpeak);
2023-11-30 15:56:15 +08:00
audio.Play(cueName);
2024-04-11 19:02:11 +08:00
// if (_oldestSound == audio)
// {
// _UpdateOldestAudio(audio.PlayID);
// }
}
2023-11-30 15:56:15 +08:00
else
{
2024-04-11 19:02:11 +08:00
audio = new Audio(AudioBase.AudioType.Sound, acbAsset, loop, posGo, rootGo, is3D, cueName, audioInfo);
2024-04-30 13:08:56 +08:00
audio.SetIsSpeak(isSpeak);
2024-04-11 19:02:11 +08:00
rootGo.name = "sound" + audio.audioID;
_audioDic.TryAdd(rootGo, audio);
}
#if UNITY_EDITOR
2023-11-30 15:56:15 +08:00
//go.name += "_"+ audio.audioID;
#endif
2023-11-30 15:56:15 +08:00
audio.SetPitch(pitch);
// Add it to music list
2024-04-11 19:02:11 +08:00
soundsAudio.TryAdd(audio.audioID, audio);
2023-11-30 15:56:15 +08:00
return audio.audioID;
#else
return -1;
#endif
2023-11-30 15:56:15 +08:00
}
catch (Exception e)
{
DebugUtil.LogError($"PlaySound, cueName: {cueName}, {e}");
throw;
}
}
2024-04-11 19:02:11 +08:00
private void _UpdateOldestAudio(int minID)
{
foreach (var kv in soundsAudio)
{
var curAudio = kv.Value;
if (minID == Math.Min(minID, curAudio.PlayID))
{
continue;
}
minID = curAudio.PlayID;
_oldestSound = curAudio;
}
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
2023-11-30 15:56:15 +08:00
try
{
2023-11-30 15:56:15 +08:00
List<int> keys;
// Stop and remove all non-persistent music audio
keys = new List<int>(musicAudio.Keys);
switch (curClipType)
{
2023-11-30 15:56:15 +08:00
case ClipType.AudioClip:
{
2023-11-30 15:56:15 +08:00
foreach (var key in keys)
{
2023-11-30 15:56:15 +08:00
if (musicAudio.ContainsKey(key))
{
2023-11-30 15:56:15 +08:00
var music = musicAudio[key];
if (!music.persist && music.activated)
{
Object.Destroy(music.audioSource);
musicAudio.Remove(key);
}
}
}
2023-11-30 15:56:15 +08:00
// Stop sound fx
keys = new List<int>(soundsAudio.Keys);
foreach (var key in keys)
{
2023-11-30 15:56:15 +08:00
if (soundsAudio.ContainsKey(key))
{
var sound = soundsAudio[key];
Object.Destroy(sound.audioSource);
soundsAudio.Remove(key);
}
}
2023-11-30 15:56:15 +08:00
break;
}
2023-11-30 15:56:15 +08:00
case ClipType.CriwareClip:
{
2023-11-30 15:56:15 +08:00
foreach (var key in keys)
{
2023-11-30 15:56:15 +08:00
if (musicAudio.ContainsKey(key))
{
2023-11-30 15:56:15 +08:00
var music = musicAudio[key];
if (!music.persist && music.activated)
{
Object.Destroy(music.audioSource);
musicAudio.Remove(key);
}
}
}
2023-11-30 15:56:15 +08:00
// Stop sound fx
keys = new List<int>(soundsAudio.Keys);
foreach (var key in keys)
{
2023-11-30 15:56:15 +08:00
if (soundsAudio.ContainsKey(key))
{
var sound = soundsAudio[key];
Object.Destroy(sound.audioSource);
soundsAudio.Remove(key);
}
}
2023-11-30 15:56:15 +08:00
break;
}
2023-11-30 15:56:15 +08:00
default:
break;
}
}
catch (Exception e)
{
DebugUtil.LogError(e);
throw;
}
2023-11-30 15:56:15 +08:00
}
//异步加载音频
private async UniTask<CriAtomAcbAsset> LoadAudioAsync(AudioType type, string audioName, bool is3D = false)
{
2023-11-30 15:56:15 +08:00
try
{
2023-11-30 15:56:15 +08:00
loadingAcb.Add(audioName, 1);
2023-11-30 15:56:15 +08:00
string acfName = audioName + ".acf";
await LoadAcfAsync(type, acfName);
2023-11-30 15:56:15 +08:00
string acbName = audioName + ".acb";
CriAtomAcbAsset acbAsset = await AssetManager.Instance.LoadAssetAsync<CriAtomAcbAsset>(acbName);
2024-04-11 19:02:11 +08:00
acbAsset.OnLoaded += (acb) =>
{
loadingAcb.Remove(audioName);
2024-03-26 12:22:47 +08:00
2024-04-11 19:02:11 +08:00
_isAcbLoadedDic.TryAdd(audioName, true);
_LoadedAcbAssetDic.TryAdd(audioName, acb);
var cueRef = new CriAtomCueReference(acb, 0);
AudioCriware.CueReferenceDic.TryAdd(acb, cueRef);
};
acbAsset.LoadImmediate();
// loadingAcb.Remove(audioName);
//
// _isAcbLoadedDic.TryAdd(audioName, true);
// _LoadedAcbAssetDic.TryAdd(audioName, acbAsset);
// var cueRef = new CriAtomCueReference(acbAsset, 0);
// CueReferenceDic.TryAdd(acbAsset, cueRef);
2023-11-30 15:56:15 +08:00
return acbAsset;
}
catch (Exception e)
{
DebugUtil.LogError($"LoadAudioAsync failed!!!, audioName:{audioName}, {e}");
throw;
}
}
2024-04-11 19:02:11 +08:00
private void _OnAcbLoaded()
{
}
//同步加载音频,需要已预加载资源
private CriAtomAcbAsset LoadAudio(AudioType type, string audioName, bool is3D = false)
{
// string acfName = audioName + ".acf";
// LoadAcf(type, acfName);
2023-11-30 15:56:15 +08:00
//string acbName = audioName + ".acb";
//CriAtomAcbAsset acbAsset = AssetManager.Instance.LoadAsset<CriAtomAcbAsset>(acbName);
if (_LoadedAcbAssetDic.TryGetValue(audioName, out var acbAsset))
{
return acbAsset;
}
return null;
}
private async UniTask<CriAtomAcfAsset> LoadAcfAsync(AudioType type, string audioName, bool is3D = false)
{
CriAtomAcfAsset acfAsset = await AssetManager.Instance.LoadAssetAsync<CriAtomAcfAsset>(audioName);
acfAsset.Register();
return acfAsset;
}
2023-11-30 15:56:15 +08:00
private bool CheckIsLoadedAcb(string audioName)
{
return _LoadedAcbAssetDic.ContainsKey(audioName);
}
2023-12-13 15:14:52 +08:00
private bool CheckAudioIsPlayable(DataAudio audioData)
{
if (audioData == null)
{
return false;
}
if (audioData.IsSpeak)
{
return _isOpenSpeakVoice;
}
return true;
}
//外部接口
public async UniTask<int> PlayAudio(string key, AudioCriManager.EPlayType type, GameObject posObj = null)
{
2023-11-30 15:56:15 +08:00
//全局播放挂到Audio物体上
var audioData = TableManager.Instance.Tables.Audios.GetByKey(key);
if (audioData == null)
{
DebugUtil.LogError("==== 播放的音频不存在音频Key: {0}", key);
return -1;
}
2023-12-13 15:14:52 +08:00
if (!CheckAudioIsPlayable(audioData))
{
return -1;
}
2023-11-30 15:56:15 +08:00
var audioName = audioData.Path;//Framework.Constants.AUDIO_MUSIC_PATH + audioData.Path;
2024-04-11 19:02:11 +08:00
if (!posObj)
{
int audioID;
switch (audioData.Type)
{
case (cfg.AudioCfg.AudioType.Sound):
{
2023-11-30 15:56:15 +08:00
if (CheckIsLoadedAcb(audioName))
{
2024-04-28 14:24:10 +08:00
audioID = PlaySoundCommonImmediately(audioName, audioData.CueName, audioData.IsSpeak);
2023-11-30 15:56:15 +08:00
}
else
{
2024-04-28 14:24:10 +08:00
audioID = await PlaySoundCommon(audioName, audioData.CueName, audioData.IsSpeak);
2023-11-30 15:56:15 +08:00
}
return audioID;
}
case (cfg.AudioCfg.AudioType.Music):
{
audioID = await PlayMusicCommon(audioName, audioData.CueName);
return audioID;
}
default:
break;
}
return -1;
}
2023-11-30 15:56:15 +08:00
//定点播放
switch (audioData.Type)
{
case (cfg.AudioCfg.AudioType.Sound):
{
2024-04-28 14:24:10 +08:00
int audioID = await PlaySoundCommon(audioName, posObj, audioData.CueName, audioData.IsSpeak);
return audioID;
}
case (cfg.AudioCfg.AudioType.Music):
{
2024-04-11 19:02:11 +08:00
int audioID = await PlayMusicCommon(audioName, posObj, audioData.CueName);
return audioID;
}
default:
break;
}
return -1;
2023-11-30 15:56:15 +08:00
}
public async UniTask<int> PlayAudio(string key, AudioCriManager.EPlayType type, Vector3 pos)
{
//全局播放挂到Audio物体上
var audioData = TableManager.Instance.Tables.Audios.GetByKey(key);
if (audioData == null)
{
DebugUtil.LogError("==== 播放的音频不存在音频Key: {0}", key);
return -1;
}
2023-12-13 15:14:52 +08:00
if (!CheckAudioIsPlayable(audioData))
{
return -1;
}
2023-11-30 15:56:15 +08:00
var audioName = audioData.Path;
//定点播放
// var go = new GameObject();
// go.transform.position = pos;
switch (audioData.Type)
{
case (cfg.AudioCfg.AudioType.Sound):
{
2023-11-30 15:56:15 +08:00
int audioID;
if (CheckIsLoadedAcb(audioName))
{
2024-04-28 14:24:10 +08:00
audioID = PlaySoundCommonImmediately(audioName, null, audioData.CueName, true, pos, audioData.IsSpeak);
2023-11-30 15:56:15 +08:00
}
else
{
2024-04-28 14:24:10 +08:00
audioID = await PlaySoundCommon(audioName, null, audioData.CueName, true, pos, audioData.IsSpeak);
2023-11-30 15:56:15 +08:00
}
return audioID;
}
case (cfg.AudioCfg.AudioType.Music):
{
int audioID = await PlayMusicCommon(audioName, null, audioData.CueName, true);
return audioID;
}
default:
break;
}
return -1;
}
public async UniTask<int> PlayAudio(int ID, AudioCriManager.EPlayType type, Vector3 pos)
{
//全局播放挂到Audio物体上
var audioData = TableManager.Instance.Tables.Audios.GetByID(ID);
if (audioData == null)
{
DebugUtil.LogError("==== 播放的音频不存在音频ID: {0}", ID);
return -1;
}
2023-12-13 15:14:52 +08:00
if (!CheckAudioIsPlayable(audioData))
{
return -1;
}
2023-11-30 15:56:15 +08:00
var audioName = audioData.Path;//Framework.Constants.AUDIO_MUSIC_PATH;// + audioData.Path;
//定点播放
switch (audioData.Type)
{
case (cfg.AudioCfg.AudioType.Sound):
{
2023-11-30 15:56:15 +08:00
int audioID;
if (CheckIsLoadedAcb(audioName))
{
2024-04-28 14:24:10 +08:00
audioID = PlaySoundCommonImmediately(audioName, null, audioData.CueName, true, pos, audioData.IsSpeak);
2023-11-30 15:56:15 +08:00
}
else
{
2024-04-28 14:24:10 +08:00
audioID = await PlaySoundCommon(audioName, null, audioData.CueName, true, pos, audioData.IsSpeak);
2023-11-30 15:56:15 +08:00
}
return audioID;
}
case (cfg.AudioCfg.AudioType.Music):
{
int audioID = await PlayMusicCommon(audioName, null, audioData.CueName, true);
return audioID;
}
default:
break;
}
return -1;
2023-11-30 15:56:15 +08:00
}
public async UniTask<int> PlayAudio(int ID, AudioCriManager.EPlayType type, GameObject posObj = null)
{
//全局播放挂到Audio物体上
var audioData = TableManager.Instance.Tables.Audios.GetByID(ID);
if (audioData == null)
{
DebugUtil.LogError("==== 播放的音频不存在音频Key: {0}", ID);
return -1;
}
2023-12-13 15:14:52 +08:00
if (!CheckAudioIsPlayable(audioData))
{
return -1;
}
2023-11-30 15:56:15 +08:00
var audioName = audioData.Path;//Constants.AUDIO_MUSIC_PATH + audioData.Path;
int audioID = -1;
2024-04-11 19:02:11 +08:00
if (!posObj)
{
switch (audioData.Type)
{
case (cfg.AudioCfg.AudioType.Sound):
{
2023-11-30 15:56:15 +08:00
if (CheckIsLoadedAcb(audioName))
{
2024-04-28 14:24:10 +08:00
audioID = PlaySoundCommonImmediately(audioName, audioData.CueName, audioData.IsSpeak);
2023-11-30 15:56:15 +08:00
}
else
{
2024-04-28 14:24:10 +08:00
audioID = await PlaySoundCommon(audioName, audioData.CueName, audioData.IsSpeak);
2023-11-30 15:56:15 +08:00
}
break;
}
case (cfg.AudioCfg.AudioType.Music):
{
2023-11-30 15:56:15 +08:00
audioID = await PlayMusicCommon(audioName, audioData.CueName);
break;
}
default:
break;
}
2023-11-30 15:56:15 +08:00
return audioID;
}
2023-11-30 15:56:15 +08:00
//定点播放
switch (audioData.Type)
{
case (cfg.AudioCfg.AudioType.Sound):
{
2024-04-28 14:24:10 +08:00
audioID = await PlaySoundCommon(audioName, posObj, audioData.CueName, audioData.IsSpeak);
break;
}
case (cfg.AudioCfg.AudioType.Music):
{
2024-04-11 19:02:11 +08:00
audioID = await PlayMusicCommon(audioName, posObj, audioData.CueName);
break;
}
}
2023-11-30 15:56:15 +08:00
return audioID;
}
2024-07-15 17:07:49 +08:00
2024-07-03 12:05:52 +08:00
#endregion
2023-11-30 15:56:15 +08:00
//在播放之前注册
public CriAtomExOutputAnalyzer RegisterAnalyzer()//CriAtomExOutputAnalyzer s
2023-11-30 15:56:15 +08:00
{
IsAnalyzer = true;
if (analyzer == null)
{
analyzer = new(NewAnalyzerConfig());
}
return analyzer;
//analyzer = s;
2023-11-30 15:56:15 +08:00
}
2024-03-26 12:22:47 +08:00
public void UnregisterAnalyzer()//CriAtomExOutputAnalyzer s
2023-11-30 15:56:15 +08:00
{
//s.DetachExPlayer();
2023-11-30 15:56:15 +08:00
IsAnalyzer = false;
//analyzer = null;
}
/// <summary>
/// 获取音频输出分析器配置
/// </summary>
/// <returns></returns>
private CriAtomExOutputAnalyzer.Config NewAnalyzerConfig()
{
CriAtomExOutputAnalyzer.Config config = new()
{
enableSpectrumAnalyzer = true, // 开启频谱分析
numSpectrumAnalyzerBands = 16, // 频谱分析数量SPECTRUM_SAMPLES_NUMBER
};
return config;
}
2023-11-30 15:56:15 +08:00
}
2024-04-11 19:02:11 +08:00
#region Audio类
2024-06-12 13:51:49 +08:00
public struct AudioInfo
{
public bool persist;
public float volume;
public float fadeInValue;
public float fadeOutValue;
public bool isSpeak;
}
public class Audio : AudioCriware
{
2024-06-12 13:51:49 +08:00
2024-04-11 19:02:11 +08:00
public Audio(AudioType audioType, CriAtomAcbAsset acb, bool loop, GameObject posGo, GameObject rootGo,
bool is3D, string cueName, AudioInfo audioInfo):
base(acb, loop, posGo, rootGo, is3D, cueName, audioInfo)
{
2024-04-30 13:08:56 +08:00
this.audioType = audioType;
DebugUtil.Log("音频源创建成功: " + cueName);
OnAcbLoaded(acb, cueName, loop, is3D);
}
protected override void AttachAnalyzer()
{
if (AudioManager.Instance.AudioMgrObj.IsAnalyzer && audioType == AudioType.Music)//将音频源挂到分析器上
{
DebugUtil.Log("音频源挂到分析器上: " + (AudioManager.Instance.AudioMgrObj.analyzer != null));
audioSource.AttachToAnalyzer(AudioManager.Instance.AudioMgrObj.analyzer);
}
}
}
2024-04-11 19:02:11 +08:00
#endregion