using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Threading.Tasks; using MoreMountains.Tools; using UnityEngine.Audio; using UnityEngine.SceneManagement; namespace MoreMountains.Feedbacks { /// /// This feedback will let you play a sound via the MMSoundManager. You will need a game object in your scene with a MMSoundManager object on it for this to work. /// [ExecuteAlways] [AddComponentMenu("")] [FeedbackPath("Audio/MMSoundManager Sound")] [FeedbackHelp("This feedback will let you play a sound via the MMSoundManager. You will need a game object in your scene with a MMSoundManager object on it for this to work.")] public class MMFeedbackMMSoundManagerSound : MMFeedback { /// a static bool used to disable all feedbacks of this type at once public static bool FeedbackTypeAuthorized = true; /// sets the inspector color for this feedback #if UNITY_EDITOR public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.SoundsColor; } } #endif /// the duration of this feedback is the duration of the clip being played public override float FeedbackDuration { get { return GetDuration(); } } [Header("Sound")] /// the sound clip to play [Tooltip("the sound clip to play")] public AudioClip Sfx; [Header("Random Sound")] /// an array to pick a random sfx from [Tooltip("an array to pick a random sfx from")] public AudioClip[] RandomSfx; [Header("Test")] [MMFInspectorButton("TestPlaySound")] public bool TestButton; [MMFInspectorButton("TestStopSound")] public bool TestStopButton; [Header("Volume")] /// the minimum volume to play the sound at [Tooltip("the minimum volume to play the sound at")] [Range(0f,2f)] public float MinVolume = 1f; /// the maximum volume to play the sound at [Tooltip("the maximum volume to play the sound at")] [Range(0f,2f)] public float MaxVolume = 1f; [Header("Pitch")] /// the minimum pitch to play the sound at [Tooltip("the minimum pitch to play the sound at")] [Range(-3f,3f)] public float MinPitch = 1f; /// the maximum pitch to play the sound at [Tooltip("the maximum pitch to play the sound at")] [Range(-3f,3f)] public float MaxPitch = 1f; [Header("SoundManager Options")] /// the track on which to play the sound. Pick the one that matches the nature of your sound [Tooltip("the track on which to play the sound. Pick the one that matches the nature of your sound")] public MMSoundManager.MMSoundManagerTracks MmSoundManagerTrack = MMSoundManager.MMSoundManagerTracks.Sfx; /// the ID of the sound. This is useful if you plan on using sound control feedbacks on it afterwards. [Tooltip("the ID of the sound. This is useful if you plan on using sound control feedbacks on it afterwards.")] public int ID = 0; /// the AudioGroup on which to play the sound. If you're already targeting a preset track, you can leave it blank, otherwise the group you specify here will override it. [Tooltip("the AudioGroup on which to play the sound. If you're already targeting a preset track, you can leave it blank, otherwise the group you specify here will override it.")] public AudioMixerGroup AudioGroup = null; /// if (for some reason) you've already got an audiosource and wouldn't like to use the built-in pool system, you can specify it here [Tooltip("if (for some reason) you've already got an audiosource and wouldn't like to use the built-in pool system, you can specify it here")] public AudioSource RecycleAudioSource = null; /// whether or not this sound should loop [Tooltip("whether or not this sound should loop")] public bool Loop = false; /// whether or not this sound should continue playing when transitioning to another scene [Tooltip("whether or not this sound should continue playing when transitioning to another scene")] public bool Persistent = false; /// whether or not this sound should play if the same sound clip is already playing [Tooltip("whether or not this sound should play if the same sound clip is already playing")] public bool DoNotPlayIfClipAlreadyPlaying = false; /// if this is true, this sound will stop playing when stopping the feedback [Tooltip("if this is true, this sound will stop playing when stopping the feedback")] public bool StopSoundOnFeedbackStop = false; /// if this is true, this sound won't be recycled if it's not done playing [Tooltip("if this is true, this sound won't be recycled if it's not done playing")] public bool DoNotAutoRecycleIfNotDonePlaying = false; [Header("Fade")] /// whether or not to fade this sound in when playing it [Tooltip("whether or not to fade this sound in when playing it")] public bool Fade = false; /// if fading, the volume at which to start the fade [Tooltip("if fading, the volume at which to start the fade")] [MMCondition("Fade", true)] public float FadeInitialVolume = 0f; /// if fading, the duration of the fade, in seconds [Tooltip("if fading, the duration of the fade, in seconds")] [MMCondition("Fade", true)] public float FadeDuration = 1f; /// if fading, the tween over which to fade the sound [Tooltip("if fading, the tween over which to fade the sound ")] [MMCondition("Fade", true)] public MMTweenType FadeTween = new MMTweenType(MMTween.MMTweenCurve.EaseInOutQuartic); [Header("Solo")] /// whether or not this sound should play in solo mode over its destination track. If yes, all other sounds on that track will be muted when this sound starts playing [Tooltip("whether or not this sound should play in solo mode over its destination track. If yes, all other sounds on that track will be muted when this sound starts playing")] public bool SoloSingleTrack = false; /// whether or not this sound should play in solo mode over all other tracks. If yes, all other tracks will be muted when this sound starts playing [Tooltip("whether or not this sound should play in solo mode over all other tracks. If yes, all other tracks will be muted when this sound starts playing")] public bool SoloAllTracks = false; /// if in any of the above solo modes, AutoUnSoloOnEnd will unmute the track(s) automatically once that sound stops playing [Tooltip("if in any of the above solo modes, AutoUnSoloOnEnd will unmute the track(s) automatically once that sound stops playing")] public bool AutoUnSoloOnEnd = false; [Header("Spatial Settings")] /// Pans a playing sound in a stereo way (left or right). This only applies to sounds that are Mono or Stereo. [Tooltip("Pans a playing sound in a stereo way (left or right). This only applies to sounds that are Mono or Stereo.")] [Range(-1f,1f)] public float PanStereo; /// Sets how much this AudioSource is affected by 3D spatialisation calculations (attenuation, doppler etc). 0.0 makes the sound full 2D, 1.0 makes it full 3D. [Tooltip("Sets how much this AudioSource is affected by 3D spatialisation calculations (attenuation, doppler etc). 0.0 makes the sound full 2D, 1.0 makes it full 3D.")] [Range(0f,1f)] public float SpatialBlend; [Header("Effects")] /// Bypass effects (Applied from filter components or global listener filters). [Tooltip("Bypass effects (Applied from filter components or global listener filters).")] public bool BypassEffects = false; /// When set global effects on the AudioListener will not be applied to the audio signal generated by the AudioSource. Does not apply if the AudioSource is playing into a mixer group. [Tooltip("When set global effects on the AudioListener will not be applied to the audio signal generated by the AudioSource. Does not apply if the AudioSource is playing into a mixer group.")] public bool BypassListenerEffects = false; /// When set doesn't route the signal from an AudioSource into the global reverb associated with reverb zones. [Tooltip("When set doesn't route the signal from an AudioSource into the global reverb associated with reverb zones.")] public bool BypassReverbZones = false; /// Sets the priority of the AudioSource. [Tooltip("Sets the priority of the AudioSource.")] [Range(0, 256)] public int Priority = 128; /// The amount by which the signal from the AudioSource will be mixed into the global reverb associated with the Reverb Zones. [Tooltip("The amount by which the signal from the AudioSource will be mixed into the global reverb associated with the Reverb Zones.")] [Range(0f,1.1f)] public float ReverbZoneMix = 1f; [Header("3D Sound Settings")] /// Sets the Doppler scale for this AudioSource. [Tooltip("Sets the Doppler scale for this AudioSource.")] [Range(0f,5f)] public float DopplerLevel = 1f; /// Sets the spread angle (in degrees) of a 3d stereo or multichannel sound in speaker space. [Tooltip("Sets the spread angle (in degrees) of a 3d stereo or multichannel sound in speaker space.")] [Range(0,360)] public int Spread = 0; /// Sets/Gets how the AudioSource attenuates over distance. [Tooltip("Sets/Gets how the AudioSource attenuates over distance.")] public AudioRolloffMode RolloffMode = AudioRolloffMode.Logarithmic; /// Within the Min distance the AudioSource will cease to grow louder in volume. [Tooltip("Within the Min distance the AudioSource will cease to grow louder in volume.")] public float MinDistance = 1f; /// (Logarithmic rolloff) MaxDistance is the distance a sound stops attenuating at. [Tooltip("(Logarithmic rolloff) MaxDistance is the distance a sound stops attenuating at.")] public float MaxDistance = 500f; protected AudioClip _randomClip; protected AudioSource _editorAudioSource; protected MMSoundManagerPlayOptions _options; protected AudioSource _playedAudioSource; /// /// Plays either a random sound or the specified sfx /// /// /// protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f) { if (!Active || !FeedbackTypeAuthorized) { return; } float intensityMultiplier = Timing.ConstantIntensity ? 1f : feedbacksIntensity; if (Sfx != null) { PlaySound(Sfx, position, intensityMultiplier); return; } if (RandomSfx.Length > 0) { _randomClip = RandomSfx[Random.Range(0, RandomSfx.Length)]; if (_randomClip != null) { PlaySound(_randomClip, position, intensityMultiplier); } } } /// /// On Stop, we stop our sound if needed /// /// /// protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1) { if (!Active || !FeedbackTypeAuthorized) { return; } if (StopSoundOnFeedbackStop && (_playedAudioSource != null)) { _playedAudioSource.Stop(); } } /// /// Triggers a play sound event /// /// /// /// protected virtual void PlaySound(AudioClip sfx, Vector3 position, float intensity) { if (DoNotPlayIfClipAlreadyPlaying) { if (MMSoundManager.Instance.FindByClip(sfx) != null) { return; } } float volume = Random.Range(MinVolume, MaxVolume); if (!Timing.ConstantIntensity) { volume = volume * intensity; } float pitch = Random.Range(MinPitch, MaxPitch); int timeSamples = NormalPlayDirection ? 0 : sfx.samples - 1; /*if (!NormalPlayDirection) { pitch = -pitch; }*/ _options.MmSoundManagerTrack = MmSoundManagerTrack; _options.Location = position; _options.Loop = Loop; _options.Volume = volume; _options.ID = ID; _options.Fade = Fade; _options.FadeInitialVolume = FadeInitialVolume; _options.FadeDuration = FadeDuration; _options.FadeTween = FadeTween; _options.Persistent = Persistent; _options.RecycleAudioSource = RecycleAudioSource; _options.AudioGroup = AudioGroup; _options.Pitch = pitch; _options.PanStereo = PanStereo; _options.SpatialBlend = SpatialBlend; _options.SoloSingleTrack = SoloSingleTrack; _options.SoloAllTracks = SoloAllTracks; _options.AutoUnSoloOnEnd = AutoUnSoloOnEnd; _options.BypassEffects = BypassEffects; _options.BypassListenerEffects = BypassListenerEffects; _options.BypassReverbZones = BypassReverbZones; _options.Priority = Priority; _options.ReverbZoneMix = ReverbZoneMix; _options.DopplerLevel = DopplerLevel; _options.Spread = Spread; _options.RolloffMode = RolloffMode; _options.MinDistance = MinDistance; _options.MaxDistance = MaxDistance; _options.DoNotAutoRecycleIfNotDonePlaying = DoNotAutoRecycleIfNotDonePlaying; _playedAudioSource = MMSoundManagerSoundPlayEvent.Trigger(sfx, _options); } /// /// Returns the duration of the sound, or of the longest of the random sounds /// /// protected virtual float GetDuration() { if (Sfx != null) { return Sfx.length; } float longest = 0f; if ((RandomSfx != null) && (RandomSfx.Length > 0)) { foreach (AudioClip clip in RandomSfx) { if ((clip != null) && (clip.length > longest)) { longest = clip.length; } } return longest; } return 0f; } #region TestMethods /// /// A test method that creates an audiosource, plays it, and destroys itself after play /// protected virtual async void TestPlaySound() { AudioClip tmpAudioClip = null; if (Sfx != null) { tmpAudioClip = Sfx; } if (RandomSfx.Length > 0) { tmpAudioClip = RandomSfx[Random.Range(0, RandomSfx.Length)]; } if (tmpAudioClip == null) { Debug.LogError(Label + " on " + this.gameObject.name + " can't play in editor mode, you haven't set its Sfx."); return; } float volume = Random.Range(MinVolume, MaxVolume); float pitch = Random.Range(MinPitch, MaxPitch); GameObject temporaryAudioHost = new GameObject("EditorTestAS_WillAutoDestroy"); SceneManager.MoveGameObjectToScene(temporaryAudioHost.gameObject, this.gameObject.scene); temporaryAudioHost.transform.position = this.transform.position; _editorAudioSource = temporaryAudioHost.AddComponent() as AudioSource; PlayAudioSource(_editorAudioSource, tmpAudioClip, volume, pitch, 0); float length = 1000 * tmpAudioClip.length; length = length / Mathf.Abs(pitch); await Task.Delay((int)length); DestroyImmediate(temporaryAudioHost); } /// /// A test method that stops the test sound /// protected virtual void TestStopSound() { if (_editorAudioSource != null) { _editorAudioSource.Stop(); } } /// /// Plays the audio source with the specified volume and pitch /// /// /// /// /// protected virtual void PlayAudioSource(AudioSource audioSource, AudioClip sfx, float volume, float pitch, int timeSamples) { // we set that audio source clip to the one in paramaters audioSource.clip = sfx; audioSource.timeSamples = timeSamples; // we set the audio source volume to the one in parameters audioSource.volume = volume; audioSource.pitch = pitch; // we set our loop setting audioSource.loop = false; // we start playing the sound audioSource.Play(); } #endregion } }