using Eflatun.SceneReference; using MyCollections.Managers; using MyCollections.SceneManagement; using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Audio; using UnityEngine.SceneManagement; public class AudioManager : MonoBehaviour { // Singleton instance public static AudioManager Instance { get; private set; } //Audio Mixer settings [Header("Mixer Settings")] public AudioMixer audioMixer; // Reference to AudioMixer for volume control public AudioMixerGroup musicMixerGroup; public AudioMixerGroup sfxMixerGroup; //Audio sources [Header("Audio Sources")] [SerializeField] private AudioSource musicSource; // Audio source for music [SerializeField] private AudioSource sfxSource; // Audio source for SFX [Header("Audio Clips")] public List<Sound> sounds = new List<Sound>(); // Array of sounds private Coroutine musicTransitionCoroutine; private GameStateManager gameStateManager; private bool isTransitioning = false; // Music fade duration [Header("Transition Settings")] public float musicTransitionTime = 2f; void Awake() { if (Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; DontDestroyOnLoad(gameObject); // Persist across scenes } if (musicSource == null) { //Audio Source for the music //Only one is necessary musicSource = gameObject.AddComponent<AudioSource>(); musicSource.outputAudioMixerGroup = musicMixerGroup; } InitializeSounds(); //SceneLoader } private void Start() { gameStateManager = GameStateManager.Instance; gameStateManager.OnGameStateChange += PlayMusicOnStateChange; } // Control volume via the AudioMixer public void SetVolume(string parameter, float value) { audioMixer.SetFloat(parameter, Mathf.Log10(value) * 20); // Convert linear slider value to logarithmic } public void InitializeSounds() { // Initialize each sound with its settings foreach (Sound sound in sounds) { sound.source = sound.audioMixerGroup == Sound.AudioType.SFX ? gameObject.AddComponent<AudioSource>() : musicSource; sound.source.clip = sound.clip; sound.source.volume = sound.volume; sound.source.pitch = sound.pitch; sound.source.loop = sound.loop; sound.source.outputAudioMixerGroup = sound.audioMixerGroup == Sound.AudioType.Music ? musicMixerGroup : sfxMixerGroup; } } private void Update() { if (!musicSource.isPlaying && !isTransitioning) { foreach (Sound sound in sounds) { if (sound.audioMixerGroup == Sound.AudioType.Music) { Debug.Log("I FOUND A SOUND TO PLAY"); PlayMusic(sound.name); break; } } } } public void Play(AudioSource source, string name) { Sound s = sounds.Find(sound => sound.name == name); if (s == null) { Debug.LogWarning($"Sound: {name} not found!"); return; } source.clip = s.clip; source.Play(); } public void Play(AudioSource source, AudioClip clip) { source.clip = clip; source.Play(); } //Play SFX sound public void Play(string name) { Sound s = sounds.Find(sound => sound.name == name); if (s == null) { Debug.LogWarning($"Sound: {name} not found!"); return; } s.source.Play(); } public void PlayMusic(string name) { Sound s = sounds.Find(sound => sound.name == name); if (s == null) { Debug.LogWarning($"Music: {name} not found!"); return; } musicSource.clip = s.clip; musicSource.Play(); } public void PlayMusic(Sound.AudioTag tag) { Sound s = sounds.Find(sound => sound.audioTag == tag); if (s == null) { Debug.LogWarning($"Music: {tag} not found!"); return; } // If already transitioning or playing the same music, don't restart the transition if (musicSource.isPlaying && musicSource.clip == s.clip) { return; } PlayTransitionMusic(tag); } private void PlayMusicOnStateChange(GameState newState) { switch (newState) { case(GameState.Combat): PlayMusic(Sound.AudioTag.EnterCombat); break; case (GameState.Normal): PlayMusic(Sound.AudioTag.Calm); break; case (GameState.Loading): Stop(musicSource); break; } } //Plays music public void PlayTransitionMusic(Sound.AudioTag tag) { Sound s = sounds.Find(sound => sound.audioTag == tag); if (s == null) { Debug.LogWarning($"Music with tag {tag} not found!"); return; } if (musicTransitionCoroutine != null) StopCoroutine(musicTransitionCoroutine); // Transition to the new music musicTransitionCoroutine = StartCoroutine(TransitionMusic(s)); } //Stop sound public void Stop(string name) { Sound s = sounds.Find(sound => sound.name == name); if (s == null) { Debug.LogWarning($"Sound: {name} not found!"); return; } s.source.Stop(); } public void Stop(AudioSource source) { Sound s = sounds.Find(sound => sound.name == name); if (s == null) { Debug.LogWarning($"Sound: {name} not found!"); return; } source.Stop(); } // Coroutine to handle smooth transition between music tracks private IEnumerator TransitionMusic(Sound newMusic) { isTransitioning = true; // Slight delay to give time for audio state to update yield return new WaitForSeconds(0.1f); Debug.Log("Is Music Playing: " + musicSource.isPlaying); // Fade out the current music if any is playing if (musicSource.isPlaying) { Debug.Log("Fading out current music..."); yield return StartCoroutine(FadeOut(musicSource, musicTransitionTime)); } // Set the new music clip and play it Debug.Log("Fading in new music..."); musicSource.clip = newMusic.clip; musicSource.Play(); // Fade in the new music yield return StartCoroutine(FadeIn(musicSource, musicTransitionTime)); isTransitioning = false; } //Smoothly fades Out a music private IEnumerator FadeOut(AudioSource audioSource, float duration) { float startVolume = audioSource.volume; float targetVolume = 0f; Debug.Log("Starting fade out"); for (float t = 0; t < duration; t += Time.deltaTime) { audioSource.volume = Mathf.Lerp(startVolume, targetVolume, t / duration); yield return null; } audioSource.volume = targetVolume; audioSource.Stop(); Debug.Log("Stop fade out"); } //Smoothly fades In a music private IEnumerator FadeIn(AudioSource audioSource, float duration) { float targetVolume = 1f; audioSource.volume = 0; audioSource.Play(); for (float t = 0; t < duration; t += Time.deltaTime) { audioSource.volume = Mathf.Lerp(0, targetVolume, t / duration); yield return null; } } //Load sounds when a scene or a gorup of scenes is loaded public void LoadSounds(Sound[] sceneSounds) => sounds.AddRange(sceneSounds); //Unloads sound //If a scene is unloaded, there's no need to keep sounds in memory public void UnloadSounds(Sound[] sceneSounds) { foreach (Sound sound in sceneSounds) { Sound s = sounds.Find(s => s.name == sound.name); if (s != null) sounds.Remove(s); } } } [Serializable] public class Sound { public enum AudioType { Music, SFX } // Separate music and sound effects public enum AudioTag { Calm, EnterCombat, ExitCombat} public string name; public AudioClip clip; public AudioType audioMixerGroup; public AudioTag audioTag; [Range(0f, 1f)] public float volume = 0.7f; [Range(0.1f, 3f)] public float pitch = 1f; public bool loop; public AudioSource source; }