using System.Collections.Generic; using AibisDream.FixSystem; using AibisDream.Framework; using FMOD; using FMOD.Studio; using FMODUnity; using STOP_MODE = FMOD.Studio.STOP_MODE; namespace AibisDream.Kit { public class FmodManager : Singleton, IAudioManager { private const string AmbStateName = "scene"; public string ambPath; #region Event实例 private EventInstance _ambInstance; private EventInstance _voiceInstance; private readonly Dictionary _musicDict = new(); private readonly Dictionary _sfxDict = new(); #endregion #region 事件索引 private List _removeTrigger; #endregion private void Start() { // 注册事件 RegisterEvent(); // 启动AMB InitAmb(); } private void RegisterEvent() { // 语音相关 EnumEventSystem.Global.Register(DialogEventEnum.LineStart, OnLineStart); EnumEventSystem.Global.Register(DialogEventEnum.LineShown, OnLineShown); // 场景切换相关 EnumEventSystem.Global.Register(EventEnum.SceneLoad, OnSceneLoad); EnumEventSystem.Global.Register(EventEnum.FixStateSwitch, OnFixStateChange); EnumEventSystem.Global.Register(EventEnum.SceneUnload, OnSceneUnload); } #region AMB相关 private void InitAmb() { _ambInstance = RuntimeManager.CreateInstance(FormatEventPath(ambPath)); _ambInstance.start(); } public void ChangeAmb(AmbState state) { _ambInstance.setParameterByName(AmbStateName, (float)state); } public void SetAmbParam(string paramName, float value) { _ambInstance.setParameterByName(paramName, value); } private void OnSceneLoad(string loadingScene) { // 场景加载时切换AMB var state = MatchAmbState(loadingScene); ChangeAmb(state); } private void OnSceneUnload() { ChangeAmb(AmbState.Main); } private void OnFixStateChange(FixState nextState) { // 状态切换时加载 var state = MatchAmbState(nextState); ChangeAmb(state); } #endregion #region 音乐相关 public void PlayMusic(string eventName) { var eventPath = FormatEventPath(eventName); if (_musicDict.TryGetValue(eventPath, out var oldMusic)) { oldMusic.start(); } else { var newMusic = RuntimeManager.CreateInstance(eventPath); _musicDict[eventPath] = newMusic; newMusic.start(); } } public void StopMusic(string eventName, STOP_MODE stopMode) { var eventPath = FormatEventPath(eventName); if (_musicDict.TryGetValue(eventPath, out var oldMusic)) { oldMusic.stop(stopMode); oldMusic.release(); _musicDict.Remove(eventPath); } } public void SetMusicParam(string eventName, string param, float paramValue) { var eventPath = FormatEventPath(eventName); if (_musicDict.TryGetValue(eventPath, out var music)) { music.setParameterByName(param, paramValue); } } #endregion public void OnLineStart(DialogText dialogText) { if (_voiceInstance.IsPlaying()) { _voiceInstance.stop(STOP_MODE.IMMEDIATE); _voiceInstance.release(); } if (string.IsNullOrEmpty(dialogText.actor.voicePath) || FModEx.IsEventExist(dialogText.actor.VoicePath)) { return; } _voiceInstance = RuntimeManager.CreateInstance(dialogText.actor.VoicePath); _voiceInstance.start(); } public void OnLineShown() { if (_voiceInstance.isValid()) { _voiceInstance.stop(STOP_MODE.IMMEDIATE); _voiceInstance.release(); } } public void PlaySfx(string eventName) { var eventPath = FormatEventPath(eventName); if (_sfxDict.TryGetValue(eventPath, out var oldSfx)) { oldSfx.start(); } else { var newSfx = RuntimeManager.CreateInstance(eventPath); if (newSfx.GetDescription().isOneshot(out var isOneshot) != RESULT.OK || !isOneshot) { _sfxDict[eventPath] = newSfx; } newSfx.start(); } } public void StopSfx(string eventName, STOP_MODE stopMode) { var eventPath = FormatEventPath(eventName); if (_sfxDict.TryGetValue(eventPath, out var oldSfx)) { oldSfx.stop(stopMode); oldSfx.release(); _musicDict.Remove(eventPath); } } public void SetSfxParam(string eventName, string paramName, float paramValue) { var eventPath = FormatEventPath(eventName); if (_sfxDict.TryGetValue(eventPath, out var sfx)) { sfx.setParameterByName(paramName, paramValue); } } #region 一些静态方法 private static string FormatEventPath(string eventName) { return $"event:/{eventName}"; } private static AmbState MatchAmbState(string key) { return key switch { "ExpressFixScene" => AmbState.Clinic, "ShitouHeadiFixScene" => AmbState.Clinic, "PeipeiFixScene" => AmbState.Clinic, "Bridge" => AmbState.Footbridge, "SkyBridge" => AmbState.Footbridge, "SubWay" => AmbState.Subway, "ClinicOut" => AmbState.Outside, _ => AmbState.Main }; } private static AmbState MatchAmbState(FixState fixState) { return fixState switch { FixState.Clinic => AmbState.Clinic, FixState.Engine => AmbState.Engine, FixState.BodyModule => AmbState.Body, FixState.Gear => AmbState.GearBox, FixState.UF => AmbState.UF, FixState.Eye => AmbState.Eye, FixState.Memory => AmbState.Memory, _ => AmbState.Main }; } #endregion } public interface IAudioManager { // Yarn音频接口 public void PlayMusic(string eventName); public void StopMusic(string eventName, STOP_MODE stopMode); public void SetMusicParam(string eventName, string paramName, float paramValue); // AMB参数变化 public void ChangeAmb(AmbState state); public void SetAmbParam(string paramName, float value); // 语音相关 public void OnLineStart(DialogText dialogText); public void OnLineShown(); // 交互相关 public void PlaySfx(string eventName); public void StopSfx(string eventName, STOP_MODE stopMode); public void SetSfxParam(string eventName, string paramName, float paramValue); } public class AudioData : IData { public string ambState; public List sfxNames = new(); public List musicNames = new(); public void Load() { throw new System.NotImplementedException(); } } }