//流式播放的音频管理器 using System; using System.Collections.Generic; using System.Linq; using CriWare; using Framework; using PhxhSDK; using UnityEngine; using AudioType = PhxhSDK.AudioBase.AudioType; using Object = UnityEngine.Object; public class AudioCriManager: Singlenton, IStart, IInitable, IUpdatable, IAudioPlay { public GameObject initGameObject; public GameObject AudioRoot; public GameObject CriAtomRoot; public CriAtom CriAtom; public ClipType curClipType; private AudioInst _bgmAudio; public enum EPlayType { Music, Sound, Speak } private GameObject _criError; private Dictionary _soundAudioDic; private Dictionary _musicAudioDic; private Dictionary _allAudioDic; private List _soundAudioObj; private List _musicAudioObj; private List _soundAudioQue; private Dictionary _storyAudioDic; private const int SOUND_MAX_NUM = 20; private const int MUSIC_MAX_NUM = 2; #region Property private float _vol = 1f; public float GlobalSoundsVolume { get => AudioCri.GlobalSoundVolume; set => AudioCri.GlobalSoundVolume = value; } public float GlobalSpeakVolume{ get => AudioCri.GlobalSpeakVolume; set => AudioCri.GlobalSpeakVolume = value; } public float GlobalMusicVolume { get => AudioCri.GlobalMusicVolume; set => AudioCri.GlobalMusicVolume = value; } public float GlobalVolume { get => AudioCri.GlobalVolume; set => AudioCri.GlobalVolume = value; } public bool GlobalIsOpenSpeak; public AudioInst BgmAudio => _bgmAudio; public CriAtomExOutputAnalyzer analyzer=null; public bool IsAnalyzer = false; #endregion #region Analyze //在播放之前注册 public CriAtomExOutputAnalyzer RegisterAnalyzer()//CriAtomExOutputAnalyzer s { IsAnalyzer = true; if (analyzer == null) { analyzer = new(NewAnalyzerConfig()); } return analyzer; //analyzer = s; } public void UnregisterAnalyzer()//CriAtomExOutputAnalyzer s { //s.DetachExPlayer(); IsAnalyzer = false; //analyzer = null; } /// /// 获取音频输出分析器配置 /// /// private CriAtomExOutputAnalyzer.Config NewAnalyzerConfig() { CriAtomExOutputAnalyzer.Config config = new() { enableSpectrumAnalyzer = true, // 开启频谱分析 numSpectrumAnalyzerBands = 16, // 频谱分析数量SPECTRUM_SAMPLES_NUMBER }; return config; } #endregion #region Framework public void Start() { if (!AudioRoot) { curClipType = ClipType.CriwareClip; AudioRoot = new GameObject(); AudioRoot.name = "Audio(Singleton)"; Object.DontDestroyOnLoad(AudioRoot); if (curClipType == ClipType.CriwareClip) { _criError = new GameObject(); _criError.name = "CriwareError"; _criError.AddComponent(); Object.DontDestroyOnLoad(_criError); } var initialize = GameObject.Find("CriWareLibraryInitializer"); Object.DontDestroyOnLoad(initialize); CriAtomRoot = GameObject.Find("CriAtom"); CriAtom = CriAtomRoot.GetComponent(); Object.DontDestroyOnLoad(CriAtomRoot); } // CriAtomRoot = new GameObject() // { // name = "CriAtom" // }; // CriAtom = CriAtomRoot.AddComponent(); // CriAtom.AddCueSheet() // for (int i = 0; i < SOUND_MAX_NUM; i++) // { // var go = new GameObject // { // name = "Sound" + (i+1) // }; // go.transform.SetParent(AudioRoot.transform); // } // // for (int i = 0; i < MUSIC_MAX_NUM; i++) // { // var go = new GameObject // { // name = "Music" + (i+1) // }; // go.transform.SetParent(AudioRoot.transform); // } } public void Init() { _soundAudioDic = new Dictionary(); _musicAudioDic = new Dictionary(); _allAudioDic = new Dictionary(); _soundAudioObj = new(); _musicAudioObj = new(); _storyAudioDic = new(); } public void Release() { } public void Update(float dt) { foreach (var kv in _musicAudioDic) { var audio = kv.Value; if (!audio.IsStopped) { audio.Update(dt); } } foreach (var kv in _soundAudioDic) { var audio = kv.Value; if (!audio.IsStopped) { audio.Update(dt); } } foreach (var kv in _storyAudioDic) { var audio = kv.Value; if (!audio.IsStopped) { audio.Update(dt); } } } #endregion #region LoadAsset private string _GetCriPath(string name) { var commonStr = "CueSheet_"; var strArr = name.Split('_'); var pre = strArr[0]; if (pre != null) { if (pre == "Voice") { return "CueSheet_Voice"; } if (pre == "bgm") { return "CueSheet_bgm"; } if (pre == "Sound") { return "CueSheet_Sound"; } if (pre == "ev") { return "CueSheet_ev"; } } return ""; } private string _GetAcbPath(string name) { var path = _GetCriPath(name); if (string.IsNullOrEmpty(path)) { DebugUtil.LogError($"获取不到对应的ACB文件,key: {name}"); return ""; } return path + ".acb"; } private string _GetAwbPath(string name) { var path = _GetCriPath(name); if (string.IsNullOrEmpty(path)) { DebugUtil.LogError($"获取不到对应的AWB文件,key: {name}"); return ""; } return path + ".awb"; } private string _GetAcfPath(string name) { var path = _GetCriPath(name); if (path == null) { DebugUtil.LogError($"获取不到对应的ACF文件,key: {name}"); return ""; } return path + ".acf"; } #endregion #region AudioObj /// /// 获取可用的Audio /// /// /// private AudioInst _GetUsableAudio(AudioBase.AudioType audioType) { var freeAudio = _GetFreeAudio(audioType); return freeAudio?? _CreateNewAudio(audioType); } private Dictionary _GetAudioDic(AudioBase.AudioType audioType) { switch (audioType) { case AudioBase.AudioType.Music: return _musicAudioDic; case AudioBase.AudioType.Sound: return _soundAudioDic; default: { DebugUtil.LogError("获取AudioDic出错!!!传入AudioType有误!"); return null; } } } private AudioInst _GetFreeAudio(AudioBase.AudioType audioType) { var dic = _GetAudioDic(audioType); if (dic != null) { foreach (var kv in dic) { var audio = kv.Value; if (audio.IsStopped) { return audio; } } } return null; } private AudioInst _CreateStoryAudio(GameObject posGo = null) { var rootGo = new GameObject() { name = "AudioStory" }; rootGo.transform.SetParent(AudioRoot.transform); var audio = new AudioInst(AudioBase.AudioType.Sound, rootGo, null); rootGo.name += audio.audioID; _storyAudioDic.TryAdd(audio.audioID, audio); _allAudioDic.Add(audio.audioID, audio); return audio; } private AudioInst _CreateNewAudio(AudioBase.AudioType audioType) { var rootGo = new GameObject() { name = "Audio" }; rootGo.transform.SetParent(AudioRoot.transform); var audio = new AudioInst(audioType, rootGo, null); if (audioType == AudioBase.AudioType.Music) { rootGo.name = "music"; rootGo.name += audio.audioID; _musicAudioDic.TryAdd(audio.audioID, audio); _musicAudioObj.Add(rootGo); if (IsAnalyzer) { rootGo.GetComponent().AttachToAnalyzer(analyzer); } } if (audioType == AudioBase.AudioType.Sound) { rootGo.name = "Sound"; rootGo.name += audio.audioID; _soundAudioDic.TryAdd(audio.audioID, audio); _soundAudioObj.Add(rootGo); } _allAudioDic.Add(audio.audioID, audio); return audio; } #endregion #region Play /// /// 调用接口,传obj /// /// /// /// /// private int _PlayAudio(string key, EPlayType type, GameObject posObj = null, bool isFade = false) { if (string.IsNullOrEmpty(key)) { return -1; } if (CriAtom) { var cueSheetName = _GetCriPath(key); if (!string.IsNullOrEmpty(cueSheetName)) { if (CriAtom.GetCueSheetInternal(cueSheetName) == null) { var acbPath = _GetAcbPath(key); var awbPath = _GetAwbPath(key); if (string.IsNullOrEmpty(acbPath) || string.IsNullOrEmpty(awbPath)) { return -1; } var cueSheet = CriAtom.AddCueSheet(cueSheetName, acbPath, awbPath, null); } } var criCueSheet = CriAtom.GetCueSheetInternal(cueSheetName); if (criCueSheet != null && criCueSheet.acb != null) { var cueInfoList = CriAtom.GetCueSheetInternal(cueSheetName).acb.GetCueInfoList(); var cueInfo = Array.Find(cueInfoList, (cue) => cue.name == key ); if (cueInfo.name == null) { DebugUtil.LogWarning($"Can not Find Criware Key:{key}"); return -1; } } else { DebugUtil.LogWarning($"Can not Find Criware Key:{key}"); return -1; } } string path = _GetCriPath(key); switch (type) { case EPlayType.Music: { return _PlayMusic(key, path, posObj, isFade); } case EPlayType.Sound: { return _PlaySound(key, path, posObj, isFade); } case EPlayType.Speak: { return _PlaySpeakSound(key, path, posObj, isFade); } default: break; } return -1; } /// /// 调用接口,传位置 /// /// /// /// /// private int _PlayAudio(string key, EPlayType type, Vector3 pos, bool isFade = false) { if (CriAtom) { var cueSheetName = _GetCriPath(key); if (CriAtom.GetCueSheetInternal(cueSheetName) == null) { var acbPath = _GetAcbPath(key); var awbPath = _GetAwbPath(key); if (string.IsNullOrEmpty(acbPath) || string.IsNullOrEmpty(awbPath)) { return -1; } var cueSheet = CriAtom.AddCueSheet(cueSheetName, acbPath, awbPath, null); } var cueInfoList = CriAtom.GetCueSheetInternal(cueSheetName).acb.GetCueInfoList(); var cueInfo = Array.Find(cueInfoList, (cue) => cue.name == key ); if (cueInfo.name == null) { DebugUtil.LogWarning($"Can not Find Criware Key:{key}"); return -1; } } string path = _GetCriPath(key); switch (type) { case EPlayType.Music: { return _PlayMusic(key, path, pos); } case EPlayType.Sound: { return _PlaySound(key, path, pos); } case EPlayType.Speak: { return _PlaySpeakSound(key, path, pos); } default: break; } return -1; } private int _PlayMusic(string key, string path, GameObject posObj = null, bool isFade = false, float volume = 1f) { if (!isFade) { if (_bgmAudio != null) { _bgmAudio.Stop(); } AudioInfo audioInfo = new AudioInfo() { persist = true, volume = 1, fadeInValue = 0.3f, fadeOutValue = 0.3f, }; var audio = _GetUsableAudio(AudioBase.AudioType.Music); audio.SetPosObj(posObj); audio.SetIsSpeak(false); audio.SetIsLoop(true); audio.SetVolume(volume); if (_bgmAudio != null && _bgmAudio != audio) { _bgmAudio.Stop(); } audio.Play(path, key); _bgmAudio = audio; return audio.audioID; } else { AudioInfo audioInfo = new AudioInfo() { persist = true, volume = 1, fadeInValue = 0.3f, fadeOutValue = 0.3f, }; var audio = _GetUsableAudio(AudioBase.AudioType.Music); audio.SetPosObj(posObj); audio.SetIsSpeak(false); audio.SetIsLoop(true); if (_bgmAudio != null && _bgmAudio != audio) { _bgmAudio.Stop(); } //audio.SetIsFadeIn(true); audio.PlayWithFade(path, key); _bgmAudio = audio; return audio.audioID; } } private int _PlayMusic(string key, string path, Vector3 pos, bool isFade = false, float volume = 1f) { if (_bgmAudio != null) { _bgmAudio.Stop(); } AudioInfo audioInfo = new AudioInfo() { persist = true, volume = 1, fadeInValue = 0.3f, fadeOutValue = 0.3f, }; var audio = _GetUsableAudio(AudioBase.AudioType.Music); audio.SetPos(pos); audio.SetIsSpeak(false); audio.SetIsLoop(true); if (_bgmAudio != null && _bgmAudio != audio) { _bgmAudio.Stop(); } if (isFade) { audio.PlayWithFade(path, key); } else { audio.Play(path, key); } _bgmAudio = audio; return audio.audioID; } private int _PlaySound(string key, string path, GameObject posObj = null, bool isFade = false, float volume = 1f) { AudioInfo audioInfo = new AudioInfo() { persist = true, volume = 1, fadeInValue = 0.3f, fadeOutValue = 0.3f, }; var audio = _GetUsableAudio(AudioBase.AudioType.Sound); audio.SetPosObj(posObj); audio.SetIsSpeak(false); audio.SetIsLoop(false); if (posObj) { audio.SetIs3D(true); } if (isFade) { audio.SetVolume(0); audio.PlayWithFade(path, key); } else { audio.SetVolume(volume); audio.Play(path, key); } return audio.audioID; } private int _PlaySound(string key, string path, Vector3 pos, bool isFade = false, float volume = 1f) { AudioInfo audioInfo = new AudioInfo() { persist = true, volume = 1, fadeInValue = 0.3f, fadeOutValue = 0.3f, }; var audio = _GetUsableAudio(AudioBase.AudioType.Sound); audio.SetPos(pos); audio.SetIsLoop(false); audio.SetIsSpeak(false); audio.SetIs3D(true); if (isFade) { audio.SetVolume(0); audio.PlayWithFade(path, key); } else { audio.SetVolume(volume); audio.Play(path, key); } return audio.audioID; } private int _PlaySpeakSound(string key, string path, GameObject posObj = null, bool isFade = false, float volume = 1f) { AudioInfo audioInfo = new AudioInfo() { persist = true, volume = 1, fadeInValue = 0.3f, fadeOutValue = 0.3f, }; var audio = _GetUsableAudio(AudioBase.AudioType.Sound); audio.SetPosObj(posObj); audio.SetIsSpeak(true); audio.SetIsLoop(false); if (isFade) { audio.SetVolume(0); audio.PlayWithFade(path, key); } else { audio.SetVolume(volume); audio.Play(path, key); } return -1; } private int _PlaySpeakSound(string key, string path, Vector3 pos, bool isFade = false, float volume = 1f) { AudioInfo audioInfo = new AudioInfo() { persist = true, volume = 1, fadeInValue = 0.3f, fadeOutValue = 0.3f, }; var audio = _GetUsableAudio(AudioBase.AudioType.Sound); audio.SetPos(pos); audio.SetIsLoop(false); audio.SetIsSpeak(true); if (isFade) { audio.SetVolume(0); audio.PlayWithFade(path, key); } else { audio.SetVolume(volume); audio.Play(path, key); } return -1; } private void _PlayAudioByID(int id, string key, EPlayType type, GameObject posObj = null) { if (_soundAudioDic.TryGetValue(id, out var audio)) { } } #endregion #region API public int PlayAudio(string key, EPlayType type, GameObject posObj = null, bool isFade = false) { return _PlayAudio(key, type, posObj, isFade); } public int PlayAudio(string key, EPlayType type, Vector3 pos, bool isFade = false) { return _PlayAudio(key, type, pos, isFade); } public int PlayAudio() { return -1; } public AudioInst GetAudioByID(EPlayType audioType, int id) { if (audioType == EPlayType.Music) { if (!_musicAudioDic.ContainsKey(id)) { return null; } return _musicAudioDic[id]; } if (audioType == EPlayType.Sound || audioType == EPlayType.Speak) { if (!_soundAudioDic.ContainsKey(id)) { return null; } return _soundAudioDic[id]; } return null; } public void StopMusicById(int audioID) { if (audioID >= 0) { if(_musicAudioDic.TryGetValue(audioID, out var audio)) { audio.Stop(); } } } public void StopSoundByID(int audioID) { if (audioID >= 0) { if(_soundAudioDic.TryGetValue(audioID, out var audio)) { audio.Stop(); } } } public void StopByID(int audioID) { if (audioID >= 0) { if(_musicAudioDic.TryGetValue(audioID, out var audio)) { audio.Stop(); } if (_soundAudioDic.TryGetValue(audioID, out var soundAudio)) { soundAudio.Stop(); } } } public void StopAllMusic() { if (_bgmAudio != null) { _bgmAudio.Stop(); } // foreach (var kv in _musicAudioDic) // { // var audio = kv.Value; // audio.Stop(); // } } public void StopAllSounds() { foreach (var kv in _soundAudioDic) { var audio = kv.Value; audio.Stop(); } } public void StopAll() { foreach (var kv in _allAudioDic) { var audio = kv.Value; audio.Stop(); } } public void ResumeAllMusic() { if (_bgmAudio != null) { _bgmAudio.Resume(); } } public void StopBGM() { _bgmAudio.Stop(); } public void AfterSwitchMainCamera(Camera camera) { var listener = camera.GetComponent(); if (!listener) { camera.gameObject.AddComponent(); } } public CriAtomExAcb GetAcb(string cueSheetName) { return CriAtom.GetAcb(cueSheetName); } public AudioInst GetStoryAudioInst() { return _CreateStoryAudio(); } public void ReleaseStoryAudios() { foreach (var kv in _storyAudioDic) { var audio = kv.Value; Object.Destroy(audio.RootGo); _allAudioDic.Remove(audio.audioID); } _storyAudioDic.Clear(); } public void PlayByCueName(int audioID, string cueName, bool isFade = false) { if (_allAudioDic.TryGetValue(audioID, out var audio)) { var cueSheet = _GetCriPath(cueName); if (isFade) { audio.PlayWithFade(cueSheet, cueName); } else { audio.Play(cueSheet, cueName); } } } public void ReleaseMusicAudios() { var musicAudioList = _musicAudioDic.ToList(); for (int i = musicAudioList.Count - 1; i >= 0; i--) { var kv = musicAudioList[i]; var audio = kv.Value; var audioID = kv.Key; audio.Stop(); _musicAudioDic.Remove(audioID); _allAudioDic.Remove(audioID); Object.Destroy(audio.RootGo); } _musicAudioObj.Clear(); _musicAudioDic.Clear(); } public void ReleaseSoundsAudios() { var soundAudioList = _soundAudioDic.ToList(); for (int i = soundAudioList.Count - 1; i >= 0; i--) { var kv = soundAudioList[i]; var audio = kv.Value; var audioID = kv.Key; audio.Stop(); _soundAudioDic.Remove(audioID); _allAudioDic.Remove(audioID); Object.Destroy(audio.RootGo); } _soundAudioObj.Clear(); _soundAudioDic.Clear(); } public void ReleaseAllAudios() { ReleaseMusicAudios(); ReleaseSoundsAudios(); } public long GetCueLength(string cueSheet, string cueName) { var acb = CriAtom.GetCueSheetInternal(cueSheet).acb; if (acb.GetCueInfo(cueName, out var cueInfo)) { var length = cueInfo.length / 1000; return length; } return -1; } #endregion } public class AudioInst : AudioCri { public AudioInst(AudioType audioType, GameObject rootGo, GameObject posGo, AudioInfo audioInfo = new(), bool loop = false, bool is3D = false):base(audioType, rootGo, posGo, audioInfo, loop, is3D) { } }