1079 lines
43 KiB
C#
1079 lines
43 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Audio;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
namespace MoreMountains.Tools
|
|
{
|
|
/// <summary>
|
|
/// A simple yet powerful sound manager, that will let you play sounds with an event based approach and performance in mind.
|
|
///
|
|
/// Features :
|
|
///
|
|
/// - Play/stop/pause/resume/free sounds
|
|
/// - Full control : loop, volume, pitch, pan, spatial blend, bypasses, priority, reverb, doppler level, spread, rolloff mode, distance
|
|
/// - 2D & 3D spatial support
|
|
/// - Built-in pooling, automatically recycle a set of audio sources for maximum performance
|
|
/// - Built in audio mixer and groups, with ready-made tracks (Master, Music, SFX, UI), and options to play on more groups if needed
|
|
/// - Stop/pause/resume/free entire tracks
|
|
/// - Stop/pause/resume/free all sounds at once
|
|
/// - Mute / set volume entire tracks
|
|
/// - Save and load settings, with auto save / auto load mechanics built-in
|
|
/// - Fade in/out sounds
|
|
/// - Fade in/out tracks
|
|
/// - Solo mode : play a sound with one or all tracks muted, then unmute them automatically afterwards
|
|
/// - PlayOptions struct
|
|
/// - Option to have sounds persist across scene loads and from scene to scene
|
|
/// - Inspector controls for tracks (volume, mute, unmute, play, pause, stop, resume, free, number of sounds)
|
|
/// - MMSfxEvents
|
|
/// - MMSoundManagerEvents : mute track, control track, save, load, reset, stop persistent sounds
|
|
/// </summary>
|
|
[AddComponentMenu("More Mountains/Tools/Audio/MMSoundManager")]
|
|
public class MMSoundManager : MMPersistentSingleton<MMSoundManager>,
|
|
MMEventListener<MMSoundManagerTrackEvent>,
|
|
MMEventListener<MMSoundManagerEvent>,
|
|
MMEventListener<MMSoundManagerSoundControlEvent>,
|
|
MMEventListener<MMSoundManagerSoundFadeEvent>,
|
|
MMEventListener<MMSoundManagerAllSoundsControlEvent>,
|
|
MMEventListener<MMSoundManagerTrackFadeEvent>
|
|
{
|
|
/// the possible ways to manage a track
|
|
public enum MMSoundManagerTracks { Sfx, Music, UI, Master, Other}
|
|
|
|
[Header("Settings")]
|
|
/// the current sound settings
|
|
[Tooltip("the current sound settings ")]
|
|
public MMSoundManagerSettingsSO settingsSo;
|
|
|
|
[Header("Pool")]
|
|
/// the size of the AudioSource pool, a reserve of ready-to-use sources that will get recycled. Should be approximately equal to the maximum amount of sounds that you expect to be playing at once
|
|
[Tooltip("the size of the AudioSource pool, a reserve of ready-to-use sources that will get recycled. Should be approximately equal to the maximum amount of sounds that you expect to be playing at once")]
|
|
public int AudioSourcePoolSize = 10;
|
|
/// whether or not the pool can expand (create new audiosources on demand). In a perfect world you'd want to avoid this, and have a sufficiently big pool, to avoid costly runtime creations.
|
|
[Tooltip("whether or not the pool can expand (create new audiosources on demand). In a perfect world you'd want to avoid this, and have a sufficiently big pool, to avoid costly runtime creations.")]
|
|
public bool PoolCanExpand = true;
|
|
|
|
protected MMSoundManagerAudioPool _pool;
|
|
protected GameObject _tempAudioSourceGameObject;
|
|
protected MMSoundManagerSound _sound;
|
|
protected List<MMSoundManagerSound> _sounds;
|
|
protected AudioSource _tempAudioSource;
|
|
|
|
#region Initialization
|
|
|
|
/// <summary>
|
|
/// On Awake we initialize our manager
|
|
/// </summary>
|
|
protected override void Awake()
|
|
{
|
|
base.Awake();
|
|
InitializeSoundManager();
|
|
}
|
|
|
|
/// <summary>
|
|
/// On Start we load and apply our saved settings if needed.
|
|
/// This is done on Start and not Awake because of a bug in Unity's AudioMixer API
|
|
/// </summary>
|
|
protected virtual void Start()
|
|
{
|
|
if ((settingsSo != null) && (settingsSo.Settings.AutoLoad))
|
|
{
|
|
settingsSo.LoadSoundSettings();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes the pool, fills it, registers to the scene loaded event
|
|
/// </summary>
|
|
protected virtual void InitializeSoundManager()
|
|
{
|
|
if (_pool == null)
|
|
{
|
|
_pool = new MMSoundManagerAudioPool();
|
|
}
|
|
_sounds = new List<MMSoundManagerSound>();
|
|
_pool.FillAudioSourcePool(AudioSourcePoolSize, this.transform);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region PlaySound
|
|
|
|
/// <summary>
|
|
/// Plays a sound, separate options object signature
|
|
/// </summary>
|
|
/// <param name="audioClip"></param>
|
|
/// <param name="options"></param>
|
|
/// <returns></returns>
|
|
public virtual AudioSource PlaySound(AudioClip audioClip, MMSoundManagerPlayOptions options)
|
|
{
|
|
return PlaySound(audioClip, options.MmSoundManagerTrack, options.Location,
|
|
options.Loop, options.Volume, options.ID,
|
|
options.Fade, options.FadeInitialVolume, options.FadeDuration, options.FadeTween,
|
|
options.Persistent,
|
|
options.RecycleAudioSource, options.AudioGroup,
|
|
options.Pitch, options.PanStereo, options.SpatialBlend,
|
|
options.SoloSingleTrack, options.SoloAllTracks, options.AutoUnSoloOnEnd,
|
|
options.BypassEffects, options.BypassListenerEffects, options.BypassReverbZones, options.Priority,
|
|
options.ReverbZoneMix,
|
|
options.DopplerLevel, options.Spread, options.RolloffMode, options.MinDistance, options.MaxDistance
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Plays a sound, signature with all options
|
|
/// </summary>
|
|
/// <param name="audioClip"></param>
|
|
/// <param name="mmSoundManagerTrack"></param>
|
|
/// <param name="location"></param>
|
|
/// <param name="loop"></param>
|
|
/// <param name="volume"></param>
|
|
/// <param name="ID"></param>
|
|
/// <param name="fade"></param>
|
|
/// <param name="fadeInitialVolume"></param>
|
|
/// <param name="fadeDuration"></param>
|
|
/// <param name="fadeTween"></param>
|
|
/// <param name="persistent"></param>
|
|
/// <param name="recycleAudioSource"></param>
|
|
/// <param name="audioGroup"></param>
|
|
/// <param name="pitch"></param>
|
|
/// <param name="panStereo"></param>
|
|
/// <param name="spatialBlend"></param>
|
|
/// <param name="soloSingleTrack"></param>
|
|
/// <param name="soloAllTracks"></param>
|
|
/// <param name="autoUnSoloOnEnd"></param>
|
|
/// <param name="bypassEffects"></param>
|
|
/// <param name="bypassListenerEffects"></param>
|
|
/// <param name="bypassReverbZones"></param>
|
|
/// <param name="priority"></param>
|
|
/// <param name="reverbZoneMix"></param>
|
|
/// <param name="dopplerLevel"></param>
|
|
/// <param name="spread"></param>
|
|
/// <param name="rolloffMode"></param>
|
|
/// <param name="minDistance"></param>
|
|
/// <param name="maxDistance"></param>
|
|
/// <returns></returns>
|
|
public virtual AudioSource PlaySound(AudioClip audioClip, MMSoundManagerTracks mmSoundManagerTrack, Vector3 location,
|
|
bool loop = false, float volume = 1.0f, int ID = 0,
|
|
bool fade = false, float fadeInitialVolume = 0f, float fadeDuration = 1f, MMTweenType fadeTween = null,
|
|
bool persistent = false,
|
|
AudioSource recycleAudioSource = null, AudioMixerGroup audioGroup = null,
|
|
float pitch = 1f, float panStereo = 0f, float spatialBlend = 0.0f,
|
|
bool soloSingleTrack = false, bool soloAllTracks = false, bool autoUnSoloOnEnd = false,
|
|
bool bypassEffects = false, bool bypassListenerEffects = false, bool bypassReverbZones = false, int priority = 128, float reverbZoneMix = 1f,
|
|
float dopplerLevel = 1f, int spread = 0, AudioRolloffMode rolloffMode = AudioRolloffMode.Logarithmic, float minDistance = 1f, float maxDistance = 500f
|
|
)
|
|
{
|
|
if (!audioClip) { return null; }
|
|
|
|
// audio source setup ---------------------------------------------------------------------------------
|
|
|
|
// we reuse an audiosource if one is passed in parameters
|
|
AudioSource audioSource = recycleAudioSource;
|
|
|
|
if (audioSource == null)
|
|
{
|
|
// we pick an idle audio source from the pool if possible
|
|
audioSource = _pool.GetAvailableAudioSource(PoolCanExpand, this.transform);
|
|
if ((audioSource != null) && (!loop))
|
|
{
|
|
recycleAudioSource = audioSource;
|
|
// we destroy the host after the clip has played (if it not tag for reusability.
|
|
StartCoroutine(_pool.AutoDisableAudioSource(audioClip.length, audioSource.gameObject));
|
|
}
|
|
}
|
|
|
|
// we create an audio source if needed
|
|
if (audioSource == null)
|
|
{
|
|
_tempAudioSourceGameObject = new GameObject("MMAudio_"+audioClip.name);
|
|
audioSource = _tempAudioSourceGameObject.AddComponent<AudioSource>();
|
|
}
|
|
|
|
// audio source settings ---------------------------------------------------------------------------------
|
|
|
|
audioSource.transform.position = location;
|
|
audioSource.time = 0.0f;
|
|
audioSource.clip = audioClip;
|
|
audioSource.pitch = pitch;
|
|
audioSource.spatialBlend = spatialBlend;
|
|
audioSource.panStereo = panStereo;
|
|
audioSource.loop = loop;
|
|
audioSource.bypassEffects = bypassEffects;
|
|
audioSource.bypassListenerEffects = bypassListenerEffects;
|
|
audioSource.bypassReverbZones = bypassReverbZones;
|
|
audioSource.priority = priority;
|
|
audioSource.reverbZoneMix = reverbZoneMix;
|
|
audioSource.dopplerLevel = dopplerLevel;
|
|
audioSource.spread = spread;
|
|
audioSource.rolloffMode = rolloffMode;
|
|
audioSource.minDistance = minDistance;
|
|
audioSource.maxDistance = maxDistance;
|
|
|
|
// track and volume ---------------------------------------------------------------------------------
|
|
|
|
if (settingsSo != null)
|
|
{
|
|
audioSource.outputAudioMixerGroup = settingsSo.MasterAudioMixerGroup;
|
|
switch (mmSoundManagerTrack)
|
|
{
|
|
case MMSoundManagerTracks.Master:
|
|
audioSource.outputAudioMixerGroup = settingsSo.MasterAudioMixerGroup;
|
|
break;
|
|
case MMSoundManagerTracks.Music:
|
|
audioSource.outputAudioMixerGroup = settingsSo.MusicAudioMixerGroup;
|
|
break;
|
|
case MMSoundManagerTracks.Sfx:
|
|
audioSource.outputAudioMixerGroup = settingsSo.SfxAudioMixerGroup;
|
|
break;
|
|
case MMSoundManagerTracks.UI:
|
|
audioSource.outputAudioMixerGroup = settingsSo.UIAudioMixerGroup;
|
|
break;
|
|
}
|
|
}
|
|
if (audioGroup) { audioSource.outputAudioMixerGroup = audioGroup; }
|
|
audioSource.volume = volume;
|
|
|
|
// we start playing the sound
|
|
audioSource.Play();
|
|
|
|
// we destroy the host after the clip has played if it was a one time AS.
|
|
if (!loop && !recycleAudioSource)
|
|
{
|
|
Destroy(_tempAudioSourceGameObject, audioClip.length);
|
|
}
|
|
|
|
// we fade the sound in if needed
|
|
if (fade)
|
|
{
|
|
FadeSound(audioSource, fadeDuration, fadeInitialVolume, volume, fadeTween);
|
|
}
|
|
|
|
// we handle soloing
|
|
if (soloSingleTrack)
|
|
{
|
|
MuteSoundsOnTrack(mmSoundManagerTrack, true, 0f);
|
|
audioSource.mute = false;
|
|
if (autoUnSoloOnEnd)
|
|
{
|
|
MuteSoundsOnTrack(mmSoundManagerTrack, false, audioClip.length);
|
|
}
|
|
}
|
|
else if (soloAllTracks)
|
|
{
|
|
MuteAllSounds();
|
|
audioSource.mute = false;
|
|
if (autoUnSoloOnEnd)
|
|
{
|
|
StartCoroutine(MuteAllSoundsCoroutine(audioClip.length, false));
|
|
}
|
|
}
|
|
|
|
// we prepare for storage
|
|
_sound.ID = ID;
|
|
_sound.Track = mmSoundManagerTrack;
|
|
_sound.Source = audioSource;
|
|
_sound.Persistent = persistent;
|
|
|
|
// we check if that audiosource is already being tracked in _sounds
|
|
bool alreadyIn = false;
|
|
for (int i = 0; i < _sounds.Count; i++)
|
|
{
|
|
if (_sounds[i].Source == audioSource)
|
|
{
|
|
_sounds[i] = _sound;
|
|
alreadyIn = true;
|
|
}
|
|
}
|
|
|
|
if (!alreadyIn)
|
|
{
|
|
_sounds.Add(_sound);
|
|
}
|
|
|
|
// we return the audiosource reference
|
|
return audioSource;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SoundControls
|
|
|
|
/// <summary>
|
|
/// Pauses the specified audiosource
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
public virtual void PauseSound(AudioSource source)
|
|
{
|
|
source.Pause();
|
|
}
|
|
|
|
/// <summary>
|
|
/// resumes play on the specified audio source
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
public virtual void ResumeSound(AudioSource source)
|
|
{
|
|
source.Play();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stops the specified audio source
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
public virtual void StopSound(AudioSource source)
|
|
{
|
|
source.Stop();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Frees a specific sound, stopping it and returning it to the pool
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
public virtual void FreeSound(AudioSource source)
|
|
{
|
|
source.Stop();
|
|
if (!_pool.FreeSound(source))
|
|
{
|
|
Destroy(source.gameObject);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TrackControls
|
|
|
|
/// <summary>
|
|
/// Mutes an entire track
|
|
/// </summary>
|
|
/// <param name="track"></param>
|
|
public virtual void MuteTrack(MMSoundManagerTracks track)
|
|
{
|
|
ControlTrack(track, ControlTrackModes.Mute, 0f);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unmutes an entire track
|
|
/// </summary>
|
|
/// <param name="track"></param>
|
|
public virtual void UnmuteTrack(MMSoundManagerTracks track)
|
|
{
|
|
ControlTrack(track, ControlTrackModes.Unmute, 0f);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the volume of an entire track
|
|
/// </summary>
|
|
/// <param name="track"></param>
|
|
/// <param name="volume"></param>
|
|
public virtual void SetTrackVolume(MMSoundManagerTracks track, float volume)
|
|
{
|
|
ControlTrack(track, ControlTrackModes.SetVolume, volume);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the current volume of a track
|
|
/// </summary>
|
|
/// <param name="track"></param>
|
|
/// <param name="volume"></param>
|
|
public virtual float GetTrackVolume(MMSoundManagerTracks track, bool mutedVolume)
|
|
{
|
|
switch (track)
|
|
{
|
|
case MMSoundManagerTracks.Master:
|
|
if (mutedVolume)
|
|
{
|
|
return settingsSo.Settings.MutedMasterVolume;
|
|
}
|
|
else
|
|
{
|
|
return settingsSo.Settings.MasterVolume;
|
|
}
|
|
case MMSoundManagerTracks.Music:
|
|
if (mutedVolume)
|
|
{
|
|
return settingsSo.Settings.MutedMusicVolume;
|
|
}
|
|
else
|
|
{
|
|
return settingsSo.Settings.MusicVolume;
|
|
}
|
|
case MMSoundManagerTracks.Sfx:
|
|
if (mutedVolume)
|
|
{
|
|
return settingsSo.Settings.MutedSfxVolume;
|
|
}
|
|
else
|
|
{
|
|
return settingsSo.Settings.SfxVolume;
|
|
}
|
|
case MMSoundManagerTracks.UI:
|
|
if (mutedVolume)
|
|
{
|
|
return settingsSo.Settings.MutedUIVolume;
|
|
}
|
|
else
|
|
{
|
|
return settingsSo.Settings.UIVolume;
|
|
}
|
|
}
|
|
|
|
return 1f;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Pauses all sounds on a track
|
|
/// </summary>
|
|
/// <param name="track"></param>
|
|
public virtual void PauseTrack(MMSoundManagerTracks track)
|
|
{
|
|
foreach (MMSoundManagerSound sound in _sounds)
|
|
{
|
|
if (sound.Track == track)
|
|
{
|
|
sound.Source.Pause();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Plays or resumes all sounds on a track
|
|
/// </summary>
|
|
/// <param name="track"></param>
|
|
public virtual void PlayTrack(MMSoundManagerTracks track)
|
|
{
|
|
foreach (MMSoundManagerSound sound in _sounds)
|
|
{
|
|
if (sound.Track == track)
|
|
{
|
|
sound.Source.Play();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stops all sounds on a track
|
|
/// </summary>
|
|
/// <param name="track"></param>
|
|
public virtual void StopTrack(MMSoundManagerTracks track)
|
|
{
|
|
foreach (MMSoundManagerSound sound in _sounds)
|
|
{
|
|
if (sound.Track == track)
|
|
{
|
|
sound.Source.Stop();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stops all sounds on a track, and returns them to the pool
|
|
/// </summary>
|
|
/// <param name="track"></param>
|
|
public virtual void FreeTrack(MMSoundManagerTracks track)
|
|
{
|
|
foreach (MMSoundManagerSound sound in _sounds)
|
|
{
|
|
if (sound.Track == track)
|
|
{
|
|
sound.Source.Stop();
|
|
sound.Source.gameObject.SetActive(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Mutes the music track, QoL method ready to bind to a UnityEvent
|
|
/// </summary>
|
|
public virtual void MuteMusic() { MuteTrack(MMSoundManagerTracks.Music); }
|
|
|
|
/// <summary>
|
|
/// Unmutes the music track, QoL method ready to bind to a UnityEvent
|
|
/// </summary>
|
|
public virtual void UnmuteMusic() { UnmuteTrack(MMSoundManagerTracks.Music); }
|
|
|
|
/// <summary>
|
|
/// Mutes the sfx track, QoL method ready to bind to a UnityEvent
|
|
/// </summary>
|
|
public virtual void MuteSfx() { MuteTrack(MMSoundManagerTracks.Sfx); }
|
|
|
|
|
|
/// <summary>
|
|
/// Unmutes the sfx track, QoL method ready to bind to a UnityEvent
|
|
/// </summary>
|
|
public virtual void UnmuteSfx() { UnmuteTrack(MMSoundManagerTracks.Sfx); }
|
|
|
|
/// <summary>
|
|
/// Mutes the UI track, QoL method ready to bind to a UnityEvent
|
|
/// </summary>
|
|
public virtual void MuteUI() { MuteTrack(MMSoundManagerTracks.UI); }
|
|
|
|
/// <summary>
|
|
/// Unmutes the UI track, QoL method ready to bind to a UnityEvent
|
|
/// </summary>
|
|
public virtual void UnmuteUI() { UnmuteTrack(MMSoundManagerTracks.UI); }
|
|
|
|
/// <summary>
|
|
/// Mutes the master track, QoL method ready to bind to a UnityEvent
|
|
/// </summary>
|
|
public virtual void MuteMaster() { MuteTrack(MMSoundManagerTracks.Master); }
|
|
|
|
/// <summary>
|
|
/// Unmutes the master track, QoL method ready to bind to a UnityEvent
|
|
/// </summary>
|
|
public virtual void UnmuteMaster() { UnmuteTrack(MMSoundManagerTracks.Master); }
|
|
|
|
|
|
/// <summary>
|
|
/// Sets the volume of the Music track to the specified value, QoL method, ready to bind to a UnityEvent
|
|
/// </summary>
|
|
public virtual void SetVolumeMusic(float newVolume) { SetTrackVolume(MMSoundManagerTracks.Music, newVolume);}
|
|
/// <summary>
|
|
/// Sets the volume of the SFX track to the specified value, QoL method, ready to bind to a UnityEvent
|
|
/// </summary>
|
|
public virtual void SetVolumeSfx(float newVolume) { SetTrackVolume(MMSoundManagerTracks.Sfx, newVolume);}
|
|
/// <summary>
|
|
/// Sets the volume of the UI track to the specified value, QoL method, ready to bind to a UnityEvent
|
|
/// </summary>
|
|
public virtual void SetVolumeUI(float newVolume) { SetTrackVolume(MMSoundManagerTracks.UI, newVolume);}
|
|
/// <summary>
|
|
/// Sets the volume of the Master track to the specified value, QoL method, ready to bind to a UnityEvent
|
|
/// </summary>
|
|
public virtual void SetVolumeMaster(float newVolume) { SetTrackVolume(MMSoundManagerTracks.Master, newVolume);}
|
|
|
|
|
|
/// <summary>
|
|
/// A method that will let you mute/unmute a track, or set it to a specified volume
|
|
/// </summary>
|
|
public enum ControlTrackModes { Mute, Unmute, SetVolume }
|
|
protected virtual void ControlTrack(MMSoundManagerTracks track, ControlTrackModes trackMode, float volume = 0.5f)
|
|
{
|
|
string target = "";
|
|
float savedVolume = 0f;
|
|
|
|
switch (track)
|
|
{
|
|
case MMSoundManagerTracks.Master:
|
|
target = settingsSo.Settings.MasterVolumeParameter;
|
|
if (trackMode == ControlTrackModes.Mute) { settingsSo.TargetAudioMixer.GetFloat(target, out settingsSo.Settings.MutedMasterVolume); settingsSo.Settings.MasterOn = false; }
|
|
else if (trackMode == ControlTrackModes.Unmute) { savedVolume = settingsSo.Settings.MutedMasterVolume; settingsSo.Settings.MasterOn = true; }
|
|
break;
|
|
case MMSoundManagerTracks.Music:
|
|
target = settingsSo.Settings.MusicVolumeParameter;
|
|
if (trackMode == ControlTrackModes.Mute) { settingsSo.TargetAudioMixer.GetFloat(target, out settingsSo.Settings.MutedMusicVolume); settingsSo.Settings.MusicOn = false; }
|
|
else if (trackMode == ControlTrackModes.Unmute) { savedVolume = settingsSo.Settings.MutedMusicVolume; settingsSo.Settings.MusicOn = true; }
|
|
break;
|
|
case MMSoundManagerTracks.Sfx:
|
|
target = settingsSo.Settings.SfxVolumeParameter;
|
|
if (trackMode == ControlTrackModes.Mute) { settingsSo.TargetAudioMixer.GetFloat(target, out settingsSo.Settings.MutedSfxVolume); settingsSo.Settings.SfxOn = false; }
|
|
else if (trackMode == ControlTrackModes.Unmute) { savedVolume = settingsSo.Settings.MutedSfxVolume; settingsSo.Settings.SfxOn = true; }
|
|
break;
|
|
case MMSoundManagerTracks.UI:
|
|
target = settingsSo.Settings.UIVolumeParameter;
|
|
if (trackMode == ControlTrackModes.Mute) { settingsSo.TargetAudioMixer.GetFloat(target, out settingsSo.Settings.MutedUIVolume); settingsSo.Settings.UIOn = false; }
|
|
else if (trackMode == ControlTrackModes.Unmute) { savedVolume = settingsSo.Settings.MutedUIVolume; settingsSo.Settings.UIOn = true; }
|
|
break;
|
|
}
|
|
|
|
switch (trackMode)
|
|
{
|
|
case ControlTrackModes.Mute:
|
|
settingsSo.SetTrackVolume(track, 0f);
|
|
break;
|
|
case ControlTrackModes.Unmute:
|
|
settingsSo.SetTrackVolume(track, settingsSo.MixerVolumeToNormalized(savedVolume));
|
|
break;
|
|
case ControlTrackModes.SetVolume:
|
|
settingsSo.SetTrackVolume(track, volume);
|
|
break;
|
|
}
|
|
|
|
settingsSo.GetTrackVolumes();
|
|
|
|
if (settingsSo.Settings.AutoSave)
|
|
{
|
|
settingsSo.SaveSoundSettings();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Fades
|
|
|
|
/// <summary>
|
|
/// Fades an entire track over the specified duration towards the desired finalVolume
|
|
/// </summary>
|
|
/// <param name="track"></param>
|
|
/// <param name="duration"></param>
|
|
/// <param name="initialVolume"></param>
|
|
/// <param name="finalVolume"></param>
|
|
/// <param name="tweenType"></param>
|
|
public virtual void FadeTrack(MMSoundManagerTracks track, float duration, float initialVolume = 0f, float finalVolume = 1f, MMTweenType tweenType = null)
|
|
{
|
|
StartCoroutine(FadeTrackCoroutine(track, duration, initialVolume, finalVolume, tweenType));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fades a target sound towards a final volume over time
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
/// <param name="duration"></param>
|
|
/// <param name="initialVolume"></param>
|
|
/// <param name="finalVolume"></param>
|
|
/// <param name="tweenType"></param>
|
|
public virtual void FadeSound(AudioSource source, float duration, float initialVolume, float finalVolume, MMTweenType tweenType)
|
|
{
|
|
StartCoroutine(FadeCoroutine(source, duration, initialVolume, finalVolume, tweenType));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fades an entire track over time
|
|
/// </summary>
|
|
/// <param name="track"></param>
|
|
/// <param name="duration"></param>
|
|
/// <param name="initialVolume"></param>
|
|
/// <param name="finalVolume"></param>
|
|
/// <param name="tweenType"></param>
|
|
/// <returns></returns>
|
|
protected virtual IEnumerator FadeTrackCoroutine(MMSoundManagerTracks track, float duration, float initialVolume, float finalVolume, MMTweenType tweenType)
|
|
{
|
|
float startedAt = Time.unscaledTime;
|
|
if (tweenType == null)
|
|
{
|
|
tweenType = new MMTweenType(MMTween.MMTweenCurve.EaseInOutQuartic);
|
|
}
|
|
while (Time.unscaledTime - startedAt <= duration)
|
|
{
|
|
float elapsedTime = Time.unscaledTime - startedAt;
|
|
float newVolume = MMTween.Tween(elapsedTime, 0f, duration, initialVolume, finalVolume, tweenType);
|
|
settingsSo.SetTrackVolume(track, newVolume);
|
|
yield return null;
|
|
}
|
|
settingsSo.SetTrackVolume(track, finalVolume);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fades an audiosource's volume over time
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
/// <param name="duration"></param>
|
|
/// <param name="initialVolume"></param>
|
|
/// <param name="finalVolume"></param>
|
|
/// <param name="tweenType"></param>
|
|
/// <returns></returns>
|
|
protected virtual IEnumerator FadeCoroutine(AudioSource source, float duration, float initialVolume, float finalVolume, MMTweenType tweenType)
|
|
{
|
|
float startedAt = Time.unscaledTime;
|
|
if (tweenType == null)
|
|
{
|
|
tweenType = new MMTweenType(MMTween.MMTweenCurve.EaseInOutQuartic);
|
|
}
|
|
while (Time.unscaledTime - startedAt <= duration)
|
|
{
|
|
float elapsedTime = Time.unscaledTime - startedAt;
|
|
float newVolume = MMTween.Tween(elapsedTime, 0f, duration, initialVolume, finalVolume, tweenType);
|
|
source.volume = newVolume;
|
|
yield return null;
|
|
}
|
|
source.volume = finalVolume;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Solo
|
|
|
|
/// <summary>
|
|
/// Mutes all sounds playing on a specific track
|
|
/// </summary>
|
|
/// <param name="track"></param>
|
|
/// <param name="mute"></param>
|
|
/// <param name="delay"></param>
|
|
public virtual void MuteSoundsOnTrack(MMSoundManagerTracks track, bool mute, float delay = 0f)
|
|
{
|
|
StartCoroutine(MuteSoundsOnTrackCoroutine(track, mute, delay));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Mutes all sounds playing on the MMSoundManager
|
|
/// </summary>
|
|
/// <param name="mute"></param>
|
|
public virtual void MuteAllSounds(bool mute = true)
|
|
{
|
|
StartCoroutine(MuteAllSoundsCoroutine(0f, mute));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Mutes all sounds on the specified track after an optional delay
|
|
/// </summary>
|
|
/// <param name="track"></param>
|
|
/// <param name="mute"></param>
|
|
/// <param name="delay"></param>
|
|
/// <returns></returns>
|
|
protected virtual IEnumerator MuteSoundsOnTrackCoroutine(MMSoundManagerTracks track, bool mute, float delay)
|
|
{
|
|
if (delay > 0)
|
|
{
|
|
yield return MMCoroutine.WaitForUnscaled(delay);
|
|
}
|
|
|
|
foreach (MMSoundManagerSound sound in _sounds)
|
|
{
|
|
if (sound.Track == track)
|
|
{
|
|
sound.Source.mute = mute;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Mutes all sounds after an optional delay
|
|
/// </summary>
|
|
/// <param name="delay"></param>
|
|
/// <param name="mute"></param>
|
|
/// <returns></returns>
|
|
protected virtual IEnumerator MuteAllSoundsCoroutine(float delay, bool mute = true)
|
|
{
|
|
if (delay > 0)
|
|
{
|
|
yield return MMCoroutine.WaitForUnscaled(delay);
|
|
}
|
|
foreach (MMSoundManagerSound sound in _sounds)
|
|
{
|
|
sound.Source.mute = mute;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Find
|
|
|
|
/// <summary>
|
|
/// Returns an audio source played with the specified ID, if one is found
|
|
/// </summary>
|
|
/// <param name="ID"></param>
|
|
/// <returns></returns>
|
|
public virtual AudioSource FindByID(int ID)
|
|
{
|
|
foreach (MMSoundManagerSound sound in _sounds)
|
|
{
|
|
if (sound.ID == ID)
|
|
{
|
|
return sound.Source;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns an audio source played with the specified ID, if one is found
|
|
/// </summary>
|
|
/// <param name="ID"></param>
|
|
/// <returns></returns>
|
|
public virtual AudioSource FindByClip(AudioClip clip)
|
|
{
|
|
foreach (MMSoundManagerSound sound in _sounds)
|
|
{
|
|
if (sound.Source.clip == clip)
|
|
{
|
|
return sound.Source;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AllSoundsControls
|
|
|
|
/// <summary>
|
|
/// Pauses all sounds playing on the MMSoundManager
|
|
/// </summary>
|
|
public virtual void PauseAllSounds()
|
|
{
|
|
foreach (MMSoundManagerSound sound in _sounds)
|
|
{
|
|
sound.Source.Pause();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Pauses all sounds playing on the MMSoundManager
|
|
/// </summary>
|
|
public virtual void PlayAllSounds()
|
|
{
|
|
foreach (MMSoundManagerSound sound in _sounds)
|
|
{
|
|
sound.Source.Play();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stops all sounds playing on the MMSoundManager
|
|
/// </summary>
|
|
public virtual void StopAllSounds()
|
|
{
|
|
foreach (MMSoundManagerSound sound in _sounds)
|
|
{
|
|
sound.Source.Stop();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stops all sounds and returns them to the pool
|
|
/// </summary>
|
|
public virtual void FreeAllSounds()
|
|
{
|
|
foreach (MMSoundManagerSound sound in _sounds)
|
|
{
|
|
if (sound.Source != null)
|
|
{
|
|
FreeSound(sound.Source);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stops all sounds except the persistent ones, and returns them to the pool
|
|
/// </summary>
|
|
public virtual void FreeAllSoundsButPersistent()
|
|
{
|
|
foreach (MMSoundManagerSound sound in _sounds)
|
|
{
|
|
if ((!sound.Persistent) && (sound.Source != null))
|
|
{
|
|
FreeSound(sound.Source);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stops all looping sounds and returns them to the pool
|
|
/// </summary>
|
|
public virtual void FreeAllLoopingSounds()
|
|
{
|
|
foreach (MMSoundManagerSound sound in _sounds)
|
|
{
|
|
if ((sound.Source.loop) && (sound.Source != null))
|
|
{
|
|
FreeSound(sound.Source);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Events
|
|
|
|
/// <summary>
|
|
/// Registered on enable, triggers every time a new scene is loaded
|
|
/// At which point we free all sounds except the persistent ones
|
|
/// </summary>
|
|
protected virtual void OnSceneLoaded(Scene arg0, LoadSceneMode loadSceneMode)
|
|
{
|
|
FreeAllSoundsButPersistent();
|
|
}
|
|
|
|
public virtual void OnMMEvent(MMSoundManagerTrackEvent soundManagerTrackEvent)
|
|
{
|
|
switch (soundManagerTrackEvent.TrackEventType)
|
|
{
|
|
case MMSoundManagerTrackEventTypes.MuteTrack:
|
|
MuteTrack(soundManagerTrackEvent.Track);
|
|
break;
|
|
case MMSoundManagerTrackEventTypes.UnmuteTrack:
|
|
UnmuteTrack(soundManagerTrackEvent.Track);
|
|
break;
|
|
case MMSoundManagerTrackEventTypes.SetVolumeTrack:
|
|
SetTrackVolume(soundManagerTrackEvent.Track, soundManagerTrackEvent.Volume);
|
|
break;
|
|
case MMSoundManagerTrackEventTypes.PlayTrack:
|
|
PlayTrack(soundManagerTrackEvent.Track);
|
|
break;
|
|
case MMSoundManagerTrackEventTypes.PauseTrack:
|
|
PauseTrack(soundManagerTrackEvent.Track);
|
|
break;
|
|
case MMSoundManagerTrackEventTypes.StopTrack:
|
|
StopTrack(soundManagerTrackEvent.Track);
|
|
break;
|
|
case MMSoundManagerTrackEventTypes.FreeTrack:
|
|
FreeTrack(soundManagerTrackEvent.Track);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public virtual void OnMMEvent(MMSoundManagerEvent soundManagerEvent)
|
|
{
|
|
switch (soundManagerEvent.EventType)
|
|
{
|
|
case MMSoundManagerEventTypes.SaveSettings:
|
|
SaveSettings();
|
|
break;
|
|
case MMSoundManagerEventTypes.LoadSettings:
|
|
settingsSo.LoadSoundSettings();
|
|
break;
|
|
case MMSoundManagerEventTypes.ResetSettings:
|
|
settingsSo.ResetSoundSettings();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Save sound settings to file
|
|
/// </summary>
|
|
public virtual void SaveSettings()
|
|
{
|
|
settingsSo.SaveSoundSettings();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads sound settings from file
|
|
/// </summary>
|
|
public virtual void LoadSettings()
|
|
{
|
|
settingsSo.LoadSoundSettings();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes any saved sound settings
|
|
/// </summary>
|
|
public virtual void ResetSettings()
|
|
{
|
|
settingsSo.ResetSoundSettings();
|
|
}
|
|
|
|
public virtual void OnMMEvent(MMSoundManagerSoundControlEvent soundControlEvent)
|
|
{
|
|
if (soundControlEvent.TargetSource == null)
|
|
{
|
|
_tempAudioSource = FindByID(soundControlEvent.SoundID);
|
|
}
|
|
else
|
|
{
|
|
_tempAudioSource = soundControlEvent.TargetSource;
|
|
}
|
|
|
|
if (_tempAudioSource != null)
|
|
{
|
|
switch (soundControlEvent.MMSoundManagerSoundControlEventType)
|
|
{
|
|
case MMSoundManagerSoundControlEventTypes.Pause:
|
|
PauseSound(_tempAudioSource);
|
|
break;
|
|
case MMSoundManagerSoundControlEventTypes.Resume:
|
|
ResumeSound(_tempAudioSource);
|
|
break;
|
|
case MMSoundManagerSoundControlEventTypes.Stop:
|
|
StopSound(_tempAudioSource);
|
|
break;
|
|
case MMSoundManagerSoundControlEventTypes.Free:
|
|
FreeSound(_tempAudioSource);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual void OnMMEvent(MMSoundManagerTrackFadeEvent trackFadeEvent)
|
|
{
|
|
FadeTrack(trackFadeEvent.Track, trackFadeEvent.FadeDuration, settingsSo.GetTrackVolume(trackFadeEvent.Track), trackFadeEvent.FinalVolume, trackFadeEvent.FadeTween);
|
|
}
|
|
|
|
public virtual void OnMMEvent(MMSoundManagerSoundFadeEvent soundFadeEvent)
|
|
{
|
|
_tempAudioSource = FindByID(soundFadeEvent.SoundID);
|
|
|
|
if (_tempAudioSource != null)
|
|
{
|
|
FadeSound(_tempAudioSource, soundFadeEvent.FadeDuration, _tempAudioSource.volume, soundFadeEvent.FinalVolume,
|
|
soundFadeEvent.FadeTween);
|
|
}
|
|
}
|
|
|
|
public virtual void OnMMEvent(MMSoundManagerAllSoundsControlEvent allSoundsControlEvent)
|
|
{
|
|
switch (allSoundsControlEvent.EventType)
|
|
{
|
|
case MMSoundManagerAllSoundsControlEventTypes.Pause:
|
|
PauseAllSounds();
|
|
break;
|
|
case MMSoundManagerAllSoundsControlEventTypes.Play:
|
|
PlayAllSounds();
|
|
break;
|
|
case MMSoundManagerAllSoundsControlEventTypes.Stop:
|
|
StopAllSounds();
|
|
break;
|
|
case MMSoundManagerAllSoundsControlEventTypes.Free:
|
|
FreeAllSounds();
|
|
break;
|
|
case MMSoundManagerAllSoundsControlEventTypes.FreeAllButPersistent:
|
|
FreeAllSoundsButPersistent();
|
|
break;
|
|
case MMSoundManagerAllSoundsControlEventTypes.FreeAllLooping:
|
|
FreeAllLoopingSounds();
|
|
break;
|
|
}
|
|
}
|
|
|
|
public virtual void OnMMSfxEvent(AudioClip clipToPlay, AudioMixerGroup audioGroup = null, float volume = 1f, float pitch = 1f)
|
|
{
|
|
MMSoundManagerPlayOptions options = MMSoundManagerPlayOptions.Default;
|
|
options.Location = this.transform.position;
|
|
options.AudioGroup = audioGroup;
|
|
options.Volume = volume;
|
|
options.Pitch = pitch;
|
|
options.MmSoundManagerTrack = MMSoundManagerTracks.Sfx;
|
|
options.Loop = false;
|
|
|
|
PlaySound(clipToPlay, options);
|
|
}
|
|
|
|
public virtual AudioSource OnMMSoundManagerSoundPlayEvent(AudioClip clip, MMSoundManagerPlayOptions options)
|
|
{
|
|
return PlaySound(clip, options);
|
|
}
|
|
|
|
/// <summary>
|
|
/// On enable we start listening for events
|
|
/// </summary>
|
|
protected virtual void OnEnable()
|
|
{
|
|
MMSfxEvent.Register(OnMMSfxEvent);
|
|
MMSoundManagerSoundPlayEvent.Register(OnMMSoundManagerSoundPlayEvent);
|
|
this.MMEventStartListening<MMSoundManagerEvent>();
|
|
this.MMEventStartListening<MMSoundManagerTrackEvent>();
|
|
this.MMEventStartListening<MMSoundManagerSoundControlEvent>();
|
|
this.MMEventStartListening<MMSoundManagerTrackFadeEvent>();
|
|
this.MMEventStartListening<MMSoundManagerSoundFadeEvent>();
|
|
this.MMEventStartListening<MMSoundManagerAllSoundsControlEvent>();
|
|
|
|
SceneManager.sceneLoaded += OnSceneLoaded;
|
|
}
|
|
|
|
/// <summary>
|
|
/// On disable we stop listening for events
|
|
/// </summary>
|
|
protected virtual void OnDisable()
|
|
{
|
|
if (_enabled)
|
|
{
|
|
MMSfxEvent.Unregister(OnMMSfxEvent);
|
|
MMSoundManagerSoundPlayEvent.Unregister(OnMMSoundManagerSoundPlayEvent);
|
|
this.MMEventStopListening<MMSoundManagerEvent>();
|
|
this.MMEventStopListening<MMSoundManagerTrackEvent>();
|
|
this.MMEventStopListening<MMSoundManagerSoundControlEvent>();
|
|
this.MMEventStopListening<MMSoundManagerTrackFadeEvent>();
|
|
this.MMEventStopListening<MMSoundManagerSoundFadeEvent>();
|
|
this.MMEventStopListening<MMSoundManagerAllSoundsControlEvent>();
|
|
|
|
SceneManager.sceneLoaded -= OnSceneLoaded;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|
|
|