Skip to content

Instantly share code, notes, and snippets.

@athiedmann
Created October 4, 2023 20:47
Show Gist options
  • Save athiedmann/a52a9754f09913022581507d77939214 to your computer and use it in GitHub Desktop.
Save athiedmann/a52a9754f09913022581507d77939214 to your computer and use it in GitHub Desktop.
Unity FMOD Audio Manager with Scene-Based Control and Event Management. Events are stored and called via scriptable objects.
using System.Collections.Generic;
using UnityEngine;
using FMODUnity;
using FMOD.Studio;
using UnityEngine.SceneManagement;
public class FMODAudioManager : MonoBehaviour
{
public bool useDebug;
public static FMODAudioManager instance { get; private set; }
public FMODEvents FMODEvents;
public FMODSnapshotEvents FMODSnapshots;
[SerializeField] EventReference fMODAmbientEvent;
private List<EventInstance> fmodEventInstances = new List<EventInstance>();
private EventInstance ambienceEventInstance;
private string sceneName;
public List<EventInstance> FMODEventInstances { get => fmodEventInstances; }
private void Awake()
{
sceneName = SceneManager.GetActiveScene().name;
if (instance != null)
{
if (useDebug)
Debug.LogError("Found more than one Audio Manager in the scene.");
Destroy(gameObject);
return;
}
instance = this;
DontDestroyOnLoad(gameObject);
}
private void Start()
{
CheckIfSceneChange();
InitializeAmbience(fMODAmbientEvent);
}
public void PlayOneShot(EventReference sound, Vector3 worldPos)
{
RuntimeManager.PlayOneShot(sound, worldPos);
}
public void PlayOneShotAttached(EventReference sound, GameObject gameObject)
{
RuntimeManager.PlayOneShotAttached(sound, gameObject);
}
public void PlayUI()
{
PlayOneShot(FMODEvents.clickButton, transform.position);
}
public void InitializeAmbience(EventReference ambienceReference)
{
if (ambienceEventInstance.isValid())
{
ambienceEventInstance.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
ambienceEventInstance.release();
}
ambienceEventInstance = CreateEventInstance(ambienceReference);
ambienceEventInstance.start();
}
public EventInstance CreateEventInstance(EventReference eventReference)
{
EventInstance eventInstance = RuntimeManager.CreateInstance(eventReference);
fmodEventInstances.Add(eventInstance);
return eventInstance;
}
public void CheckIfSceneChange()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
sceneName = SceneManager.GetActiveScene().name;
if (sceneName == "Scene_Game_Menu" && fmodEventInstances.Count > 0)
{
CleanUp();
InitializeAmbience(fMODAmbientEvent);
}
}
private void CleanUp()
{
foreach (EventInstance eventInstance in fmodEventInstances)
{
eventInstance.stop(FMOD.Studio.STOP_MODE.IMMEDIATE);
eventInstance.release();
}
fmodEventInstances.Clear();
}
private void OnDestroy()
{
CleanUp();
}
}
using FMODUnity;
using UnityEngine;
[CreateAssetMenu(fileName = "FMODEvents", menuName = "Dragon Crashers/Audio/Events")]
public class FMODEvents : ScriptableObject
{
[field: Header("UI")]
[field: SerializeField] public EventReference clickButton { get; private set; }
[field: SerializeField] public EventReference hoverButton { get; private set; }
}
using FMODUnity;
using UnityEngine;
[CreateAssetMenu(fileName = "FMODMusicEvents", menuName = "Dragon Crashers/Audio/Music")]
public class FMODMusicEvents : ScriptableObject
{
[field: Header("Level Music")]
[field: SerializeField] public EventReference skeletonLevelMusic { get; private set; }
[field: SerializeField] public EventReference dragonLevelMusic { get; private set; }
[field: SerializeField] public EventReference WinMusic { get; private set; }
[field: SerializeField] public EventReference DefeatMusic { get; private set; }
}
using System.Collections;
using UnityEngine;
using FMOD.Studio;
using FMODUnity;
using UnityEngine.SceneManagement;
public class FMODMusicManager : MonoBehaviour
{
public bool useDebug;
public static FMODMusicManager instance { get; private set; }
public FMODMusicEvents FMODMusicEvents;
[SerializeField] bool playMusicOnStart;
private EventInstance musicLevelInstance;
//private EventInstance musicVictoryDefeatInstance;
private string sceneName;
private PLAYBACK_STATE musicPlayBackState;
private bool isPlaying = false;
private bool isFadingOut = false;
public bool IsPlaying { get => isPlaying; }
private void Awake()
{
if (instance != null)
{
UseDebug("Found more than one Music Manager in the scene.");
Destroy(gameObject);
return;
}
instance = this;
DontDestroyOnLoad(gameObject);
isPlaying = false;
}
private void Start()
{
CheckIfSceneChange();
if (playMusicOnStart && string.IsNullOrEmpty(sceneName))
{
SetMusicEventForScene();
UseDebug("Play On Start called");
}
UseDebug($"Music is playing: {isPlaying}");
}
public void InitializeMusic(EventReference musicReference)
{
musicLevelInstance = FMODAudioManager.instance.CreateEventInstance(musicReference);
musicLevelInstance.start();
isPlaying = true;
UseDebug("Music Initialized and PLAYING");
}
public void PlayMusic()
{
musicLevelInstance.getPlaybackState(out musicPlayBackState);
UseDebug("Music Playback State: " + musicPlayBackState);
if (musicPlayBackState != PLAYBACK_STATE.PLAYING)
{
SetMusicEventForScene();
}
else
{
Debug.LogWarning("Music instance already playing");
}
}
public void StopMusic()
{
musicLevelInstance.getPlaybackState(out musicPlayBackState);
UseDebug("Music Playback State: " + musicPlayBackState);
if (musicPlayBackState != PLAYBACK_STATE.PLAYING)
{
musicLevelInstance.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
musicLevelInstance.release();
}
else
{
Debug.LogWarning("No music instance playing");
}
}
public void SetMusicEventForScene()
{
sceneName = SceneManager.GetActiveScene().name;
UseDebug("Current scene name: " + sceneName);
switch (sceneName)
{
case "Scene_Battle_Skeletons":
InitializeMusic(FMODMusicEvents.skeletonLevelMusic);
break;
case "Scene_Battle_Dragon":
InitializeMusic(FMODMusicEvents.dragonLevelMusic);
break;
case "Scene_Game_Menu":
InitializeMusic(FMODMusicEvents.skeletonLevelMusic);
break;
default:
Debug.LogWarning("Music returning, check if scene names have changed");
return;
}
}
public void FadeOutMusicOnSceneLoad()
{
musicLevelInstance.getPlaybackState(out musicPlayBackState);
if (musicPlayBackState == PLAYBACK_STATE.PLAYING && isPlaying)
{
StartCoroutine(FadeOutCoroutine());
}
else
{
Debug.LogWarning("musicPlayBackState is not playing anything");
return;
}
}
private IEnumerator FadeOutCoroutine()
{
isFadingOut = true;
EventInstance musicFadeOutSnapshot = FMODAudioManager.instance.CreateEventInstance(FMODAudioManager.instance.FMODSnapshots.MusicFadeOut);
musicFadeOutSnapshot.start();
float fadeDuration = 5.0f;
float elapsedTime = 0.0f;
while (elapsedTime < fadeDuration)
{
elapsedTime += Time.deltaTime;
yield return null;
}
musicLevelInstance.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
musicLevelInstance.release();
isPlaying = false;
musicFadeOutSnapshot.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT);
musicFadeOutSnapshot.release();
isFadingOut = false;
}
public void CheckIfSceneChange()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
sceneName = SceneManager.GetActiveScene().name;
if (sceneName == "Scene_Game_Menu")
{
SetMusicEventForScene();
}
}
private void UseDebug(string debugMessage)
{
if (useDebug)
{
Debug.Log(debugMessage);
}
}
}
using FMODUnity;
using UnityEngine;
[CreateAssetMenu(fileName = "FMODSnapshotEvents", menuName = "Dragon Crashers/Audio/Snapshots")]
public class FMODSnapshotEvents : ScriptableObject
{
[field: Header("Snapshots")]
[field: SerializeField] public EventReference MusicFadeOut { get; private set; }
[field: SerializeField] public EventReference DragonLevelMusicFade { get; private set; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment