// *********************************************************************** // Assembly : Unity // Author : Kimch // Created : // // Last Modified By : Kimch // Last Modified On : // *********************************************************************** // // // *********************************************************************** using System; using UnityEngine; namespace G { [RequireComponent(typeof(AudioSource))] public class SoundLayer : MonoBehaviour { private enum State { None, WaitingToPlay, FadingOut, FadingIn, Playing, Pause, Stop, Mute } private int _lastSamples; private int _numberOfPlays; private float _volume; private float _fadeDuration; private float _fadeStartTime; private float _fadeStartVolume; private State _state; private AudioSource _audioSource; /// /// Gets the number of plays. /// /// /// The number of plays. /// public int numberOfPlays { get { return _numberOfPlays; } } /// /// Gets the time samples. /// /// /// The time samples. /// public int timeSamples { get { return _audioSource.timeSamples; } } /// /// Sets the volume. /// /// /// The volume. /// public float volume { get { return _volume; } set { _volume = value; _audioSource.volume = value; } } /// /// Gets the clip. /// /// /// The clip. /// public AudioClip clip { get { return _audioSource.clip; } } /// /// Preloads the specified clip. /// /// The clip. /// if set to true [loop]. public void Preload(AudioClip clip, bool loop) { _lastSamples = 0; _numberOfPlays = 0; _fadeStartVolume = 0f; _state = State.WaitingToPlay; _audioSource.clip = clip; _audioSource.loop = loop; _audioSource.timeSamples = 0; _audioSource.volume = 0f; _audioSource.Play(); } /// /// Determines whether [is waiting to play]. /// /// public bool IsWaitingToPlay() { return _state == State.WaitingToPlay; } /// /// Determines whether [is fading in]. /// /// public bool IsFadingIn() { return _state == State.FadingIn; } /// /// Determines whether [is fading out]. /// /// public bool IsFadingOut() { return _state == State.FadingOut; } /// /// Determines whether this instance is playing. /// /// public bool IsPlaying() { return _state == State.FadingIn || _state == State.Playing; } /// /// Determines whether this instance is stopped. /// /// public bool IsStopped() { return _state != State.FadingIn && _state != State.Playing && _state != State.WaitingToPlay; } /// /// Plays the specified fade duration. /// /// Duration of the fade. public void Play(float fadeDuration) { if (_audioSource.clip) { _fadeDuration = fadeDuration; _fadeStartTime = Time.realtimeSinceStartup; _fadeStartVolume = 0f; _state = State.FadingIn; } } /// /// Plays the specified fade duration. /// /// Duration of the fade. /// The time in samples. public void Play(float fadeDuration, int timeInSamples) { if (_audioSource.clip) { int clipSamples = this.clip.samples; int modSamples = timeInSamples % clipSamples; _audioSource.timeSamples = modSamples; _numberOfPlays = (modSamples < (clipSamples >> 1) ? 1 : 0); _lastSamples = timeInSamples; this.Play(fadeDuration); } } /// /// Stops the specified fade duration. /// /// Duration of the fade. public void Stop(float fadeDuration) { _fadeDuration = fadeDuration; _fadeStartTime = Time.realtimeSinceStartup; _fadeStartVolume = _volume; _state = State.FadingOut; } /// /// Pauses the specified fade duration. /// /// Duration of the fade. public void Pause(float fadeDuration) { if (this.IsPlaying()) { _fadeDuration = fadeDuration; _fadeStartTime = Time.realtimeSinceStartup; _fadeStartVolume = _volume; _state = State.Pause; } } /// /// Mutes this instance. /// public void Mute() { _state = State.Mute; _audioSource.volume = 0f; } /// /// Checks the loop. /// private void CheckLoop() { //更新速度足够快 大于samples / 2 基本上可以做播放一次~ int timeSamples = _audioSource.timeSamples; AudioClip clip = _audioSource.clip; if (clip && timeSamples < _lastSamples - (clip.samples >> 1)) { _numberOfPlays++; } _lastSamples = timeSamples; } /// /// Updates the fade. /// /// The target volume. /// private bool UpdateFade(float targetVolume) { float timer = Time.realtimeSinceStartup - _fadeStartTime; if (timer > _fadeDuration) { _audioSource.volume = targetVolume; return false; } float t = Mathf.Log10(Mathf.Lerp(1f, 10f, timer / _fadeDuration)); _audioSource.volume = Mathf.Lerp(_fadeStartVolume, targetVolume, t); return true; } #region MONOBEHAVIOUR private void Awake() { _audioSource = this.GetComponent(); _volume = _audioSource.volume; } private void Update() { switch (_state) { case State.FadingIn: if (!this.UpdateFade(_volume)) { _state = State.Playing; } this.CheckLoop(); break; case State.Playing: if (!_audioSource.isPlaying && !_audioSource.loop) { _state = State.None; } this.CheckLoop(); break; case State.FadingOut: if (!this.UpdateFade(0f)) { _state = State.Stop; } break; case State.Stop: _audioSource.Stop(); _audioSource.clip = null; _state = State.None; break; case State.Pause: if (!this.UpdateFade(0f)) { _state = State.WaitingToPlay; } break; } } #endregion } }