You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

155 lines
4.7 KiB

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
public class AudioManager : MonoBehaviour
{
private const int MaxVirtualChannels = 1024; // Should match MAX_CHANNELS in q_sound.h
private const int MaxRealChannels = 128; // Should match MAX_DYNAMIC_CHANNELS in q_sound.h
private FMOD.System fmodSystem;
public FMOD.System FmodSystem => fmodSystem;
private static AudioManager instance;
public static AudioManager Instance
{
get
{
if (instance == null)
{
instance = FindObjectOfType<AudioManager>();
if (instance == null)
{
var gameObject = new GameObject("FMOD Audio Manager");
instance = gameObject.AddComponent<AudioManager>();
}
}
return instance;
}
}
[SerializeField, Range(0, 1)]
private float masterVolume = 1f;
private float prevMasterVolume;
private FMOD.ChannelGroup masterChannelGroup;
void Awake()
{
// Ensure FMOD is initialized the moment Instance is accessed
InitFmod();
}
void OnEnable()
{
// Ensure FMOD gets re-initialized after hot reload
InitFmod();
}
void Update()
{
if (!fmodSystem.hasHandle() || !masterChannelGroup.hasHandle())
return;
if (!Mathf.Approximately(masterVolume, prevMasterVolume))
{
masterChannelGroup.setVolume(masterVolume);
prevMasterVolume = masterVolume;
}
masterChannelGroup.getVolume(out masterVolume);
}
void OnDisable()
{
// Ensure FMOD gets closed before hot reload
CloseFmod();
}
void OnDestroy()
{
CloseFmod();
instance = null;
}
private void InitFmod()
{
if (fmodSystem.hasHandle())
return;
#if UNITY_PS4 || UNITY_PS5 || UNITY_GAMECORE
// Move FMOD mixer thread off the already heavily congested core 1
FMOD.Thread.SetAttributes(FMOD.THREAD_TYPE.MIXER, FMOD.THREAD_AFFINITY.CORE_4);
#endif
FMOD.RESULT result = FMOD.Factory.System_Create(out fmodSystem);
CheckFmodResult(result, "FMOD.Factory.System_Create");
result = fmodSystem.getVersion(out uint version);
CheckFmodResult(result, "FMOD.System.getVersion");
Debug.LogFormat("[FMOD] Initialized FMOD System version {0:X1}.{1:X2}.{2:X2}",
(version >> 16) & 0xFF, (version >> 8) & 0xFF, version & 0xFF);
result = fmodSystem.getNumDrivers(out int numDrivers);
CheckFmodResult(result, "FMOD.System.getNumDrivers");
result = fmodSystem.setOutput(numDrivers > 0 ? FMOD.OUTPUTTYPE.AUTODETECT : FMOD.OUTPUTTYPE.NOSOUND);
CheckFmodResult(result, "FMOD.System.setOutput");
result = fmodSystem.getOutput(out FMOD.OUTPUTTYPE output);
CheckFmodResult(result, "FMOD.System.getOutput");
Debug.Log($"[FMOD] Using output type: {output}");
result = fmodSystem.setSoftwareChannels(MaxRealChannels);
CheckFmodResult(result, "FMOD.System.setSoftwareChannels");
result = fmodSystem.init(MaxVirtualChannels, FMOD.INITFLAGS.VOL0_BECOMES_VIRTUAL, IntPtr.Zero);
CheckFmodResult(result, "FMOD.System.init");
result = fmodSystem.getMasterChannelGroup(out masterChannelGroup);
CheckFmodResult(result, "FMOD.System.getMasterChannelGroup");
masterChannelGroup.setVolume(masterVolume);
prevMasterVolume = masterVolume;
}
private void CheckFmodResult(FMOD.RESULT result, string cause)
{
if (result != FMOD.RESULT.OK)
{
CloseFmod();
throw new Exception($"[FMOD] Initialization failed : {cause} : {result.ToString()} : {FMOD.Error.String(result)}");
}
}
private void CloseFmod()
{
if (fmodSystem.hasHandle())
{
Debug.Log("[FMOD] Closing FMOD System");
fmodSystem.close();
fmodSystem.release();
fmodSystem.clearHandle();
}
}
#if UNITY_EDITOR || DEVELOPMENT_BUILD
void OnGUI()
{
var debug = new StringBuilder("FMOD System\n");
FMOD.Memory.GetStats(out int currentAlloc, out int maxAlloc);
debug.AppendFormat("MEMORY: cur = {0}MB, max = {1}MB\n", currentAlloc >> 20, maxAlloc >> 20);
fmodSystem.getChannelsPlaying(out int channels, out int realChannels);
debug.AppendFormat("CHANNELS: real = {0}, total = {1}\n", realChannels, channels);
GUI.Box(new Rect(0, 300, 250, 60), debug.ToString());
}
#endif
}