//********************************** 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; } } /** @} */ }