332 lines
8.7 KiB
C#
332 lines
8.7 KiB
C#
using FMOD.Studio;
|
|
using FMODUnity;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
using STOP_MODE = FMOD.Studio.STOP_MODE;
|
|
|
|
public class AudioManager : MonoBehaviour
|
|
{
|
|
|
|
//VCAs (VCA buses) are mainly used for volume control
|
|
//Regular routing buses routing are for the remaining logic, for example, within the FMOD itself to put FMOD events inside the Mixer (Mixer Routing).
|
|
//Regular routing buses are used when we make some attenuation based on parameters and write the logic in code for Unity.
|
|
|
|
private VCA masterVCA;
|
|
private VCA musicVCA;
|
|
private VCA sfxVCA;
|
|
private VCA uiVCA;
|
|
private VCA ambienceVCA;
|
|
|
|
[SerializeField]
|
|
[Header("Volume")]
|
|
[Range(0, 1)]
|
|
|
|
public float MasterVolume = 0.5f;
|
|
[Range(0, 1)]
|
|
|
|
public float MusicVolume = 0.5f;
|
|
[Range(0, 1)]
|
|
|
|
public float AmbienceVolume = 0.5f;
|
|
[Range(0, 1)]
|
|
|
|
public float SFXVolume = 0.5f;
|
|
[Range(0, 1)]
|
|
|
|
public float UIVolume = 0.5f;
|
|
[Range(0, 1)]
|
|
|
|
private Bus masterBus;
|
|
private Bus ambientBus;
|
|
private Bus musicBus;
|
|
private Bus sfxBus;
|
|
private Bus uiBus;
|
|
|
|
const string sid = "00000000-0000-0000-0000-000000000000";
|
|
static readonly Guid nullGuid = new Guid(sid);
|
|
|
|
private List<EventInstance> eventInstances = new();
|
|
class TimelineInfo
|
|
{
|
|
public FMOD.StringWrapper LastMarker = new();
|
|
}
|
|
TimelineInfo timelineInfo;
|
|
GCHandle timelineHandle;
|
|
|
|
EVENT_CALLBACK beatCallback;
|
|
|
|
private static AudioManager _instance { get; set; }
|
|
public static event Action<string> OnNewBGMMarker;
|
|
// public static AudioManager instance;
|
|
private static EventInstance musicEventInstance;
|
|
|
|
|
|
// public access for the Singleton
|
|
// and lazy instantiation if not exists
|
|
public static AudioManager Instance
|
|
{
|
|
get
|
|
{
|
|
// if exists directly return
|
|
if (_instance) return _instance;
|
|
|
|
// otherwise search it in the scene
|
|
_instance = FindObjectOfType<AudioManager>();
|
|
|
|
// found it?
|
|
if (_instance) return _instance;
|
|
|
|
// otherwise create and initialize it
|
|
CreateInstance();
|
|
|
|
return _instance;
|
|
}
|
|
}
|
|
|
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
|
private static void CreateInstance()
|
|
{
|
|
// skip if already exists
|
|
if (_instance) return;
|
|
if (SceneManager.GetActiveScene().name == "BankLoader") return;
|
|
InitializeInstance(new GameObject(nameof(AudioManager)).AddComponent<AudioManager>());
|
|
}
|
|
|
|
private static void InitializeInstance(AudioManager instance)
|
|
{
|
|
_instance = instance;
|
|
DontDestroyOnLoad(_instance.gameObject);
|
|
_instance.eventInstances = new List<EventInstance>();
|
|
|
|
|
|
_instance.masterBus = RuntimeManager.GetBus("bus:/");
|
|
_instance.musicBus = RuntimeManager.GetBus("bus:/Music");
|
|
_instance.ambientBus = RuntimeManager.GetBus("bus:/Ambiences");
|
|
_instance.sfxBus = RuntimeManager.GetBus("bus:/SFX");
|
|
_instance.uiBus = RuntimeManager.GetBus("bus:/UI");
|
|
|
|
|
|
_instance.masterVCA = RuntimeManager.GetVCA("vca:/Master");
|
|
_instance.musicVCA = RuntimeManager.GetVCA("vca:/Music");
|
|
_instance.ambienceVCA = RuntimeManager.GetVCA("vca:/Ambiences");
|
|
_instance.sfxVCA = RuntimeManager.GetVCA("vca:/SFX");
|
|
_instance.uiVCA = RuntimeManager.GetVCA("vca:/UI");
|
|
|
|
}
|
|
|
|
public void SetMasterVCA(float value)
|
|
{
|
|
masterVCA.setVolume(value);
|
|
}
|
|
|
|
public void SetMusicVCA(float value)
|
|
{
|
|
musicVCA.setVolume(value);
|
|
}
|
|
|
|
public void SetAmbientVCA(float value)
|
|
{
|
|
ambienceVCA.setVolume(value);
|
|
}
|
|
|
|
public void SetSFXVCA(float value)
|
|
{
|
|
sfxVCA.setVolume(value);
|
|
}
|
|
|
|
public void SetUIVCA(float value)
|
|
{
|
|
|
|
uiVCA.setVolume(value);
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
if (_instance && _instance != this)
|
|
{
|
|
Destroy(gameObject);
|
|
return;
|
|
}
|
|
InitializeInstance(this);
|
|
}
|
|
|
|
public EventInstance CreateInstance(EventReference eventReference)
|
|
{
|
|
EventInstance eventInstance = RuntimeManager.CreateInstance(eventReference);
|
|
eventInstances.Add(eventInstance);
|
|
return eventInstance;
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
//musicBus.setVolume(MusicVolume);
|
|
//ambientBus.setVolume(AmbienceVolume);
|
|
//sfxBus.setVolume(SFXVolume);
|
|
//uiBus.setVolume(UIVolume);
|
|
//masterBus.setVolume(MasterVolume);
|
|
|
|
|
|
//VCA volumes
|
|
masterVCA.setVolume(MasterVolume);
|
|
ambienceVCA.setVolume(AmbienceVolume);
|
|
musicVCA.setVolume(MusicVolume);
|
|
sfxVCA.setVolume(SFXVolume);
|
|
uiVCA.setVolume(UIVolume);
|
|
}
|
|
|
|
public static bool IsEventReferenceValid(EventReference eventReference)
|
|
{
|
|
return eventReference.Guid != nullGuid;
|
|
}
|
|
public static void PlayOneShot(EventReference eventReference)
|
|
{
|
|
if (eventReference.Guid != nullGuid)
|
|
RuntimeManager.PlayOneShot(eventReference);
|
|
else
|
|
{
|
|
Debug.LogWarning("EventReference is null, ignoring...");
|
|
}
|
|
}
|
|
|
|
public void PlayOneShot3D(EventReference sound, Vector3 position)
|
|
{
|
|
if (!IsEventReferenceValid(sound))
|
|
{
|
|
Debug.LogWarning("Tried to play invalid FMOD event (3D)");
|
|
return;
|
|
}
|
|
|
|
RuntimeManager.PlayOneShot(sound, position);
|
|
}
|
|
|
|
public EventInstance PlayAttachedInstance(EventReference sound, GameObject go)
|
|
{
|
|
if (!IsEventReferenceValid(sound))
|
|
{
|
|
Debug.LogWarning("Tried to play invalid FMOD event (attached)");
|
|
return default;
|
|
}
|
|
|
|
EventInstance instance = RuntimeManager.CreateInstance(sound);
|
|
RuntimeManager.AttachInstanceToGameObject(instance, go);
|
|
instance.start();
|
|
// instance.release();
|
|
|
|
eventInstances.Add(instance);
|
|
return instance;
|
|
}
|
|
|
|
public void StopInstance(EventInstance instance, STOP_MODE mode = STOP_MODE.ALLOWFADEOUT)
|
|
{
|
|
if (!instance.isValid()) return;
|
|
instance.stop(mode);
|
|
instance.release();
|
|
}
|
|
|
|
public void SetParameter(EventInstance instance, string parameterName, float value)
|
|
{
|
|
if (!instance.isValid()) return;
|
|
instance.setParameterByName(parameterName, value);
|
|
}
|
|
|
|
public void SetGlobalParameter(string parameterName, float value)
|
|
{
|
|
RuntimeManager.StudioSystem.setParameterByName(parameterName, value);
|
|
}
|
|
|
|
public void InitializeMusic(EventReference musicEventReference)
|
|
{
|
|
if (musicEventReference.Guid == nullGuid)
|
|
{
|
|
Debug.LogWarning("EventReference is null, ignoring.");
|
|
return;
|
|
}
|
|
musicEventInstance = CreateInstance(musicEventReference);
|
|
}
|
|
|
|
public void SetMusicParameter(string parameter, float value)
|
|
{
|
|
musicEventInstance.setParameterByName(parameter, value);
|
|
}
|
|
public void StartMusic()
|
|
{
|
|
if (!musicEventInstance.isValid())
|
|
{
|
|
Debug.LogWarning("Music is not initialized yet, ignoring.");
|
|
return;
|
|
}
|
|
musicEventInstance.start();
|
|
}
|
|
|
|
public int GetMusicPosition()
|
|
{
|
|
musicEventInstance.getTimelinePosition(out int position);
|
|
return position;
|
|
}
|
|
|
|
public void StopSFX()
|
|
{
|
|
sfxBus.stopAllEvents(FMOD.Studio.STOP_MODE.IMMEDIATE);
|
|
}
|
|
|
|
public void FadeOutMusic()
|
|
{
|
|
musicEventInstance.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
|
|
musicEventInstance.release();
|
|
|
|
}
|
|
|
|
public static bool IsPlaying()
|
|
{
|
|
musicEventInstance.getPlaybackState(out PLAYBACK_STATE state);
|
|
return state != PLAYBACK_STATE.STOPPED;
|
|
}
|
|
|
|
public static bool IsPlaying(EventInstance instance)
|
|
{
|
|
instance.getPlaybackState(out PLAYBACK_STATE state);
|
|
return state != PLAYBACK_STATE.STOPPED;
|
|
}
|
|
public static void Unpause()
|
|
{
|
|
musicEventInstance.setPaused(false);
|
|
}
|
|
|
|
public static void Unpause(EventInstance instance)
|
|
{
|
|
instance.setPaused(false);
|
|
}
|
|
|
|
public static void Pause()
|
|
{
|
|
musicEventInstance.setPaused(true);
|
|
}
|
|
|
|
public static void Pause(EventInstance instance)
|
|
{
|
|
instance.setPaused(true);
|
|
}
|
|
|
|
private void CleanUp()
|
|
{
|
|
if (eventInstances != null)
|
|
{
|
|
foreach (EventInstance eventInstance in eventInstances)
|
|
{
|
|
eventInstance.stop(FMOD.Studio.STOP_MODE.IMMEDIATE);
|
|
eventInstance.release();
|
|
}
|
|
}
|
|
|
|
}
|
|
private void OnDestroy()
|
|
{
|
|
CleanUp();
|
|
}
|
|
|
|
} |