//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
//**************** Copyright (c) 2016 Marko Pintera (marko.pintera@gmail.com). All rights reserved. **********************//
namespace BansheeEngine
{
/** @addtogroup Audio
* @{
*/
///
/// Valid states in which AudioSource can be in.
///
public enum AudioSourceState // Note: Must match C++ enum AudioSourceState
{
///
/// Source is currently playing.
///
Playing,
///
/// Source is currently paused (play will resume from paused point).
///
Paused,
///
/// Source is currently stopped (play will resume from start).
///
Stopped
}
///
/// Represents a source for emitting audio. Audio can be played spatially (gun shot), or normally (music). Each audio
/// source must have an AudioClip to play-back, and it can also have a position in the case of spatial(3D) audio.
///
/// Whether or not an audio source is spatial is controlled by the assigned AudioClip.The volume and the pitch of a
/// spatial audio source is controlled by its position and the AudioListener's position/direction/velocity.
///
public abstract class AudioSource : Component
{
internal NativeAudioSource native;
[SerializeField]
internal SerializableData serializableData = new SerializableData();
private Vector3 lastPosition;
private Vector3 velocity;
///
/// Audio clip that will be played.
///
public AudioClip Clip
{
get { return serializableData.audioClip; }
set
{
if (serializableData.audioClip == value)
return;
serializableData.audioClip = value;
if (native != null)
native.Clip = value;
}
}
///
/// Volume of the audio source, in [0, 1] range.
///
public float Volume
{
get { return serializableData.volume; }
set
{
if (serializableData.volume == value)
return;
serializableData.volume = value;
if (native != null)
native.Volume = value;
}
}
///
/// Pitch of the audio source.
///
public float Pitch
{
get { return serializableData.pitch; }
set
{
if (serializableData.pitch == value)
return;
serializableData.pitch = value;
if (native != null)
native.Pitch = value;
}
}
///
/// Determines whether the audio clip should loop when it finishes playing.
///
public bool Loop
{
get { return serializableData.loop; }
set
{
if (serializableData.loop == value)
return;
serializableData.loop = value;
if (native != null)
native.Loop = value;
}
}
///
/// Sets the priority of the audio source. If more audio sources are playing than supported by the hardware, some
/// might get disabled. By setting a higher priority the audio source is guaranteed to be disabled after sources
/// with lower priority.
///
public uint Priority
{
get { return serializableData.priority; }
set
{
if (serializableData.priority == value)
return;
serializableData.priority = value;
if (native != null)
native.Priority = value;
}
}
///
/// Minimum distance at which audio attenuation starts. When the listener is closer to the source than this value,
/// audio is heard at full volume. Once farther away the audio starts attenuating.
///
public float MinDistance
{
get { return serializableData.minDistance; }
set
{
if (serializableData.minDistance == value)
return;
serializableData.minDistance = value;
if (native != null)
native.MinDistance = value;
}
}
///
/// Determines how quickly does audio volume drop off as the listener moves further from the source.
///
public float Attenuation
{
get { return serializableData.attenuation; }
set
{
if (serializableData.attenuation == value)
return;
serializableData.attenuation = value;
if (native != null)
native.Attenuation = value;
}
}
///
/// Playback position in seconds.
///
public float Time
{
get
{
if (native != null)
return native.Time;
return 0.0f;
}
set
{
if (native != null)
native.Time = value;
}
}
///
/// Determines if the playback of the audio clip should start as soon as the component is initialized.
///
public bool PlayOnStart
{
get { return serializableData.playOnStart; }
set { serializableData.playOnStart = value; }
}
///
/// Returns the current state of the audio playback (playing/paused/stopped).
///
public AudioSourceState State
{
get
{
if (native != null)
return native.State;
return AudioSourceState.Stopped;
}
}
///
/// Starts playing the currently assigned audio clip.
///
public void Play()
{
if (native != null)
native.Play();
}
///
/// Pauses audio playback.
///
public void Pause()
{
if (native != null)
native.Pause();
}
///
/// Stops audio playback, rewinding it to the start.
///
public void Stop()
{
if (native != null)
native.Stop();
}
///
/// Updates the transform of the internal source representation from the transform of the component's scene
/// object.
///
protected void UpdateTransform()
{
native.Position = SceneObject.Position;
native.Velocity = velocity;
}
private void OnInitialize()
{
NotifyFlags = TransformChangedFlags.Transform;
}
private void OnUpdate()
{
Vector3 worldPos = SceneObject.Position;
velocity = (worldPos - lastPosition) / BansheeEngine.Time.FrameDelta;
lastPosition = worldPos;
}
private void OnEnable()
{
RestoreNative();
if (serializableData.playOnStart)
Play();
}
private void OnDisable()
{
DestroyNative();
}
private void OnDestroy()
{
DestroyNative();
}
private void OnTransformChanged(TransformChangedFlags flags)
{
if (!SceneObject.Active)
return;
if ((flags & (TransformChangedFlags.Parent | TransformChangedFlags.Transform)) != 0)
UpdateTransform();
}
///
/// Destroys the internal source representation.
///
private void DestroyNative()
{
if (native != null)
{
native.Destroy();
native = null;
}
}
///
/// Creates the internal representation of the source and restores the values saved by the component.
///
private void RestoreNative()
{
native = new NativeAudioSource();
native.Clip = serializableData.audioClip;
native.Volume = serializableData.volume;
native.Pitch = serializableData.pitch;
native.Loop = serializableData.loop;
native.Priority = serializableData.priority;
native.MinDistance = serializableData.minDistance;
native.Attenuation = serializableData.attenuation;
UpdateTransform();
}
///
/// Holds all data the listener component needs to persist through serialization.
///
[SerializeObject]
internal class SerializableData
{
public AudioClip audioClip;
public float volume = 1.0f;
public float pitch = 1.0f;
public bool loop = false;
public uint priority = 0;
public float minDistance = 1.0f;
public float attenuation = 1.0f;
public bool playOnStart = true;
}
}
/** @} */
}