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.
150 lines
4.5 KiB
150 lines
4.5 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;
|
|
|
|
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
|
|
}
|