442 lines
13 KiB
C#
442 lines
13 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using AibisDream.FixSystem;
|
|
using AibisDream.Framework;
|
|
using FMOD;
|
|
using FMOD.Studio;
|
|
using FMODUnity;
|
|
using UnityEngine;
|
|
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(GameLoopEnum.GameQuit, OnGameQuit);
|
|
}
|
|
|
|
private void RegisterData()
|
|
{
|
|
// 注册数据
|
|
StorageSystem.Instance.RegisterData(_audioData);
|
|
_audioData.LoadEvent += LoadData;
|
|
}
|
|
|
|
private void LoadData(AudioData data)
|
|
{
|
|
foreach (var musicEvent in _musicDict.Values)
|
|
{
|
|
musicEvent.release();
|
|
}
|
|
|
|
foreach (var sfxEvent in _sfxDict.Values)
|
|
{
|
|
sfxEvent.release();
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
public void PauseAll()
|
|
{
|
|
foreach (var music in _musicDict.Values)
|
|
{
|
|
music.setPaused(true);
|
|
}
|
|
|
|
foreach (var sfx in _sfxDict.Values)
|
|
{
|
|
sfx.setPaused(true);
|
|
}
|
|
|
|
_ambInstance.setPaused(true);
|
|
_voiceInstance.setPaused(true);
|
|
}
|
|
|
|
public void UnPauseAll()
|
|
{
|
|
foreach (var music in _musicDict.Values)
|
|
{
|
|
music.setPaused(false);
|
|
}
|
|
|
|
foreach (var sfx in _sfxDict.Values)
|
|
{
|
|
sfx.setPaused(false);
|
|
}
|
|
|
|
_ambInstance.setPaused(false);
|
|
_voiceInstance.setPaused(false);
|
|
}
|
|
|
|
#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 OnGameQuit()
|
|
{
|
|
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();
|
|
}
|
|
|
|
if (_voiceInstance.isValid())
|
|
{
|
|
_voiceInstance.stop(STOP_MODE.IMMEDIATE);
|
|
_voiceInstance.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 调整音量
|
|
|
|
public void SetVolume(float volumeValue)
|
|
{
|
|
var masterVca = RuntimeManager.GetBus("bus:/");
|
|
masterVca.setVolume(volumeValue);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#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 void StopSfxWithDelay(string key, string paramName, float paramValue, float delay, STOP_MODE stopMode = STOP_MODE.ALLOWFADEOUT)
|
|
{
|
|
if (_sfxDict.TryGetValue(key, out var sfx))
|
|
{
|
|
StartCoroutine(DelayedStop(sfx, key, paramName, paramValue, delay, stopMode));
|
|
}
|
|
}
|
|
|
|
private IEnumerator DelayedStop(EventInstance instance, string key, string paramName, float paramValue, float delay, STOP_MODE stopMode)
|
|
{
|
|
instance.setParameterByName(paramName, paramValue);
|
|
yield return new WaitForSeconds(delay);
|
|
|
|
instance.stop(stopMode);
|
|
instance.release();
|
|
RemoveSfx(key);
|
|
}
|
|
|
|
public void StopMusicWithDelay(string key, string paramName, float paramValue, float delay, STOP_MODE stopMode = STOP_MODE.ALLOWFADEOUT)
|
|
{
|
|
if (_musicDict.TryGetValue(key, out var music))
|
|
{
|
|
StartCoroutine(DelayedStopMusic(music, key, paramName, paramValue, delay, stopMode));
|
|
}
|
|
}
|
|
|
|
private IEnumerator DelayedStopMusic(EventInstance instance, string key, string paramName, float paramValue, float delay, STOP_MODE stopMode)
|
|
{
|
|
instance.setParameterByName(paramName, paramValue);
|
|
yield return new WaitForSeconds(delay);
|
|
|
|
instance.stop(stopMode);
|
|
instance.release();
|
|
RemoveMusic(key);
|
|
}
|
|
}
|
|
|
|
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 void PauseAll();
|
|
public void UnPauseAll();
|
|
}
|
|
|
|
public class AudioData : IData
|
|
{
|
|
public readonly Dictionary<string, string> sfxNames = new();
|
|
public readonly Dictionary<string, string> musicNames = new();
|
|
|
|
public event Action<AudioData> LoadEvent;
|
|
|
|
public IEnumerator Load()
|
|
{
|
|
LoadEvent?.Invoke(this);
|
|
yield break;
|
|
}
|
|
}
|
|
}
|
|
|