// This code is part of the Fungus library (https://github.com/snozbot/fungus)
// It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE)
using UnityEngine;
using System.Collections.Generic;
namespace Fungus
{
///
/// Type of audio effect to play.
///
public enum AudioMode
{
/// Use short beep sound effects.
Beeps,
/// Use long looping sound effect.
SoundEffect,
}
///
/// Manages audio effects for Dialogs.
///
public class WriterAudio : MonoBehaviour, IWriterListener
{
[Tooltip("Volume level of writing sound effects")]
[Range(0,1)]
[SerializeField] protected float volume = 1f;
[Tooltip("Loop the audio when in Sound Effect mode. Has no effect in Beeps mode.")]
[SerializeField] protected bool loop = true;
// If none is specifed then we use any AudioSource on the gameobject, and if that doesn't exist we create one.
[Tooltip("AudioSource to use for playing sound effects. If none is selected then one will be created.")]
[SerializeField] protected AudioSource targetAudioSource;
[Tooltip("Type of sound effect to play when writing text")]
[SerializeField] protected AudioMode audioMode = AudioMode.Beeps;
[Tooltip("List of beeps to randomly select when playing beep sound effects. Will play maximum of one beep per character, with only one beep playing at a time.")]
[SerializeField] protected List beepSounds = new List();
[Tooltip("Long playing sound effect to play when writing text")]
[SerializeField] protected AudioClip soundEffect;
[Tooltip("Sound effect to play on user input (e.g. a click)")]
[SerializeField] protected AudioClip inputSound;
protected float targetVolume = 0f;
// When true, a beep will be played on every written character glyph
protected bool playBeeps;
// True when a voiceover clip is playing
protected bool playingVoiceover = false;
public bool IsPlayingVoiceOver { get { return playingVoiceover; } }
// Time when current beep will have finished playing
protected float nextBeepTime;
public float GetSecondsRemaining()
{
if (IsPlayingVoiceOver)
{
return targetAudioSource.isPlaying ? targetAudioSource.clip.length - targetAudioSource.time : 0f;
}
else
{
return 0F;
}
}
protected virtual void SetAudioMode(AudioMode mode)
{
audioMode = mode;
}
protected virtual void Awake()
{
// Need to do this in Awake rather than Start due to init order issues
if (targetAudioSource == null)
{
targetAudioSource = GetComponent();
if (targetAudioSource == null)
{
targetAudioSource = gameObject.AddComponent();
}
}
targetAudioSource.volume = 0f;
}
protected virtual void Play(AudioClip audioClip)
{
if (targetAudioSource == null ||
(audioMode == AudioMode.SoundEffect && soundEffect == null && audioClip == null) ||
(audioMode == AudioMode.Beeps && beepSounds.Count == 0))
{
return;
}
playingVoiceover = false;
targetAudioSource.volume = 0f;
targetVolume = volume;
if (audioClip != null)
{
// Voice over clip provided
targetAudioSource.clip = audioClip;
targetAudioSource.loop = loop;
targetAudioSource.Play();
}
else if (audioMode == AudioMode.SoundEffect &&
soundEffect != null)
{
// Use sound effects defined in WriterAudio
targetAudioSource.clip = soundEffect;
targetAudioSource.loop = loop;
targetAudioSource.Play();
}
else if (audioMode == AudioMode.Beeps)
{
// Use beeps defined in WriterAudio
targetAudioSource.clip = null;
targetAudioSource.loop = false;
playBeeps = true;
}
}
protected virtual void Pause()
{
if (targetAudioSource == null)
{
return;
}
// There's an audible click if you call audioSource.Pause() so instead just drop the volume to 0.
targetVolume = 0f;
}
protected virtual void Stop()
{
if (targetAudioSource == null)
{
return;
}
// There's an audible click if you call audioSource.Stop() so instead we just switch off
// looping and let the audio stop automatically at the end of the clip
targetVolume = 0f;
targetAudioSource.loop = false;
playBeeps = false;
playingVoiceover = false;
}
protected virtual void Resume()
{
if (targetAudioSource == null)
{
return;
}
targetVolume = volume;
}
protected virtual void Update()
{
targetAudioSource.volume = Mathf.MoveTowards(targetAudioSource.volume, targetVolume, Time.deltaTime * 5f);
}
#region IWriterListener implementation
public virtual void OnInput()
{
if (inputSound != null)
{
// Assumes we're playing a 2D sound
AudioSource.PlayClipAtPoint(inputSound, Vector3.zero);
}
}
public virtual void OnStart(AudioClip audioClip)
{
if (playingVoiceover)
{
return;
}
Play(audioClip);
}
public virtual void OnPause()
{
if (playingVoiceover)
{
return;
}
Pause();
}
public virtual void OnResume()
{
if (playingVoiceover)
{
return;
}
Resume();
}
public virtual void OnEnd(bool stopAudio)
{
if (stopAudio)
{
Stop();
}
}
public virtual void OnGlyph()
{
if (playingVoiceover)
{
return;
}
if (playBeeps && beepSounds.Count > 0)
{
if (!targetAudioSource.isPlaying)
{
if (nextBeepTime < Time.realtimeSinceStartup)
{
targetAudioSource.clip = beepSounds[Random.Range(0, beepSounds.Count)];
if (targetAudioSource.clip != null)
{
targetAudioSource.loop = false;
targetVolume = volume;
targetAudioSource.Play();
float extend = targetAudioSource.clip.length;
nextBeepTime = Time.realtimeSinceStartup + extend;
}
}
}
}
}
public virtual void OnVoiceover(AudioClip voiceOverClip)
{
if (targetAudioSource == null)
{
return;
}
playingVoiceover = true;
targetAudioSource.volume = volume;
targetVolume = volume;
targetAudioSource.loop = false;
targetAudioSource.clip = voiceOverClip;
targetAudioSource.Play();
}
public void OnAllWordsWritten()
{
}
#endregion
}
}