Files
aibis-dream/Assets/Scripts/Framework/AudioKit/AudioManager.cs
T
2025-03-11 23:46:58 +08:00

341 lines
10 KiB
C#

using System;
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 AudioManager : Singleton<AudioManager>, IAudioManager
{
private const string AmbStateName = "scene";
public EventReference ambEvent;
#region Event实例
private EventInstance _ambInstance;
private EventInstance _voiceInstance;
private readonly Dictionary<string, EventInstance> _musicDict = new();
private readonly Dictionary<string, EventInstance> _sfxDict = new();
#endregion
#region 事件索引
private List<IUnRegister> _removeTrigger;
private readonly AudioData _audioData = new();
#endregion
private void Start()
{
// 注册事件
RegisterEvent();
// 启动AMB
InitAmb();
// 注册数据
RegisterData();
}
private void RegisterEvent()
{
// 语音相关
EnumEventSystem.Global.Register<DialogEventEnum, DialogText>(DialogEventEnum.LineStart, OnLineStart);
EnumEventSystem.Global.Register(DialogEventEnum.LineShown, OnLineShown);
// 场景切换相关
EnumEventSystem.Global.Register<EventEnum, string>(EventEnum.SceneLoad, OnSceneLoad);
EnumEventSystem.Global.Register<EventEnum, FixState>(EventEnum.FixStateSwitch, OnFixStateChange);
EnumEventSystem.Global.Register(EventEnum.SceneUnload, OnSceneUnload);
}
private void RegisterData()
{
// 注册数据
GameLoopManager.FixDataContainer.Register(_audioData);
_audioData.LoadEvent += LoadData;
}
private void LoadData(AudioData data)
{
foreach (var music in data.musicNames)
{
var instance = RuntimeManager.CreateInstance(music.Value);
instance.start();
_musicDict[music.Key] = instance;
}
foreach (var sfx in data.sfxNames)
{
var instance = RuntimeManager.CreateInstance(sfx.Value);
instance.start();
_sfxDict[sfx.Key] = instance;
}
}
#region AMB相关
private void InitAmb()
{
_ambInstance = RuntimeManager.CreateInstance(ambEvent);
_ambInstance.start();
}
public void ChangeAmb(AmbState state)
{
RuntimeManager.StudioSystem.setParameterByName(AmbStateName, (float)state);
}
public void SetGlobalParam(string paramName, float value)
{
RuntimeManager.StudioSystem.setParameterByName(paramName, value);
}
private void OnSceneLoad(string loadingScene)
{
// 场景加载时切换AMB
var state = MatchAmbState(loadingScene);
ChangeAmb(state);
}
private void OnSceneUnload()
{
ChangeAmb(AmbState.Main);
// 清除当前播放的所有东西
foreach (var music in _musicDict.Values)
{
music.stop(STOP_MODE.IMMEDIATE);
music.release();
}
foreach (var sfx in _sfxDict.Values)
{
sfx.stop(STOP_MODE.IMMEDIATE);
sfx.release();
}
_musicDict.Clear();
_sfxDict.Clear();
_audioData.musicNames.Clear();
_audioData.sfxNames.Clear();
}
private void OnFixStateChange(FixState nextState)
{
// 状态切换时加载
var state = MatchAmbState(nextState);
ChangeAmb(state);
}
#endregion
#region 音乐相关
public void PlayMusic(string eventName, string audioKey = null)
{
var eventPath = FormatEventPath(eventName);
var key = string.IsNullOrEmpty(audioKey) ? eventName : audioKey;
if (_musicDict.TryGetValue(key, out var oldMusic))
{
oldMusic.stop(STOP_MODE.IMMEDIATE);
oldMusic.release();
RemoveMusic(key);
}
var newMusic = RuntimeManager.CreateInstance(eventPath);
AddMusic(key, newMusic);
newMusic.start();
}
public void StopMusic(string key, STOP_MODE stopMode)
{
if (_musicDict.TryGetValue(key, out var oldMusic))
{
oldMusic.stop(stopMode);
oldMusic.release();
RemoveMusic(key);
}
}
public void SetMusicParam(string key, string param, float paramValue)
{
if (_musicDict.TryGetValue(key, out var music))
{
music.setParameterByName(param, paramValue);
}
}
private void RemoveMusic(string key)
{
_musicDict.Remove(key);
_audioData.musicNames.Remove(key);
}
private void AddMusic(string key, EventInstance eventInstance)
{
_musicDict[key] = eventInstance;
eventInstance.GetDescription().getPath(out var path);
_audioData.musicNames[key] = path;
}
#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, string audioKey = null)
{
var eventPath = FormatEventPath(eventName);
var key = string.IsNullOrEmpty(audioKey) ? eventName : audioKey;
if (_sfxDict.TryGetValue(key, out var oldSfx))
{
oldSfx.stop(STOP_MODE.IMMEDIATE);
oldSfx.release();
RemoveSfx(key);
}
var newSfx = RuntimeManager.CreateInstance(eventPath);
if (newSfx.GetDescription().isOneshot(out var isOneshot) != RESULT.OK || !isOneshot)
{
AddSfx(key, newSfx);
}
newSfx.start();
}
public void StopSfx(string key, STOP_MODE stopMode=STOP_MODE.IMMEDIATE)
{
if (_sfxDict.TryGetValue(key, out var oldSfx))
{
oldSfx.stop(stopMode);
oldSfx.release();
RemoveSfx(key);
}
}
public void SetSfxParam(string key, string paramName, float paramValue)
{
if (_sfxDict.TryGetValue(key, out var sfx))
{
sfx.setParameterByName(paramName, paramValue);
}
}
private void RemoveSfx(string key)
{
_sfxDict.Remove(key);
_audioData.sfxNames.Remove(key);
}
private void AddSfx(string key, EventInstance eventInstance)
{
_sfxDict[key] = eventInstance;
eventInstance.GetDescription().getPath(out var path);
_audioData.sfxNames[key] = path;
}
#region 一些静态方法
private static string FormatEventPath(string eventName)
{
return eventName.StartsWith("event:/") ? eventName : $"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,
"OutSideSceneTemp" => 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, string audioKey);
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 SetGlobalParam(string paramName, float value);
// 语音相关
public void OnLineStart(DialogText dialogText);
public void OnLineShown();
// 交互相关
public void PlaySfx(string eventName, string audioKey);
public void StopSfx(string eventName, STOP_MODE stopMode);
public void SetSfxParam(string eventName, string paramName, float paramValue);
}
public class AudioData : IData
{
public readonly Dictionary<string, string> sfxNames = new();
public readonly Dictionary<string, string> musicNames = new();
public event Action<AudioData> LoadEvent;
public void Load()
{
LoadEvent?.Invoke(this);
}
}
}