Просмотр исходного кода

Exposed AudioSource and AudioListener to managed code

BearishSun 9 лет назад
Родитель
Сommit
ab2bf04b9d

+ 2 - 2
Source/BansheeCore/Include/BsAudioSource.h

@@ -11,7 +11,7 @@ namespace BansheeEngine
 	 *  @{
 	 *  @{
 	 */
 	 */
 
 
-	/** Valid states for AudioSource. */
+	/** Valid states in which AudioSource can be in. */
 	enum class AudioSourceState
 	enum class AudioSourceState
 	{
 	{
 		Playing, /**< Source is currently playing. */
 		Playing, /**< Source is currently playing. */
@@ -24,7 +24,7 @@ namespace BansheeEngine
 	 * source must have an AudioClip to play-back, and it can also have a position in the case of spatial (3D) 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
 	 * 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.
+	 * spatial audio source is controlled by its position and the AudioListener's position/direction/velocity.
 	 */
 	 */
 	class BS_CORE_EXPORT AudioSource
 	class BS_CORE_EXPORT AudioSource
 	{
 	{

+ 1 - 1
Source/BansheeCore/Source/BsCAudioSource.cpp

@@ -10,7 +10,7 @@ using namespace std::placeholders;
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	CAudioSource::CAudioSource(const HSceneObject& parent)
 	CAudioSource::CAudioSource(const HSceneObject& parent)
-		: Component(parent)
+		: Component(parent), mVolume(1.0f), mPitch(1.0f), mLoop(false), mPriority(0), mMinDistance(1.0f), mAttenuation(1.0f)
 	{
 	{
 		setName("AudioSource");
 		setName("AudioSource");
 
 

+ 31 - 0
Source/MBansheeEditor/Inspectors/AudioListenerInspector.cs

@@ -0,0 +1,31 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /** @addtogroup Inspectors
+     *  @{
+     */
+
+    /// <summary>
+    /// Renders an inspector for the <see cref="AudioListener"/> component.
+    /// </summary>
+    [CustomInspector(typeof(AudioListener))]
+    internal class AudioListenerInspector : Inspector
+    {
+        /// <inheritdoc/>
+        protected internal override void Initialize()
+        {
+
+        }
+
+        /// <inheritdoc/>
+        protected internal override InspectableState Refresh()
+        {
+            return InspectableState.NotModified;
+        }
+    }
+
+    /** @} */
+}

+ 133 - 0
Source/MBansheeEditor/Inspectors/AudioSourceInspector.cs

@@ -0,0 +1,133 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /** @addtogroup Inspectors
+     *  @{
+     */
+
+    /// <summary>
+    /// Renders an inspector for the <see cref="AudioSource"/> component.
+    /// </summary>
+    [CustomInspector(typeof(AudioSource))]
+    internal class AudioSourceInspector : Inspector
+    {
+        private GUIResourceField audioClipField = new GUIResourceField(typeof(AudioClip), new LocEdString("Clip"));
+        private GUISliderField volumeField = new GUISliderField(0.0f, 1.0f, new LocEdString("Volume"));
+        private GUIFloatField pitchField = new GUIFloatField(new LocEdString("Pitch"));
+        private GUIToggleField loopField = new GUIToggleField(new LocEdString("Loop"));
+        private GUIIntField priorityField = new GUIIntField(new LocEdString("Priority"));
+        private GUIFloatField minDistanceField = new GUIFloatField(new LocEdString("Min. distance"));
+        private GUIFloatField attenuationField = new GUIFloatField(new LocEdString("Attenuation"));
+        
+        private InspectableState modifyState;
+        
+        /// <inheritdoc/>
+        protected internal override void Initialize()
+        {
+            BuildGUI();
+        }
+
+        /// <inheritdoc/>
+        protected internal override InspectableState Refresh()
+        {
+            AudioSource source = InspectedObject as AudioSource;
+            if (source == null)
+                return InspectableState.NotModified;
+
+            audioClipField.Value = source.Clip;
+            volumeField.Value = source.Volume;
+            pitchField.Value = source.Pitch;
+            loopField.Value = source.Loop;
+            priorityField.Value = (int)source.Priority;
+            minDistanceField.Value = source.MinDistance;
+            attenuationField.Value = source.Attenuation;
+
+            InspectableState oldState = modifyState;
+            if (modifyState.HasFlag(InspectableState.Modified))
+                modifyState = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Recreates all the GUI elements used by this inspector.
+        /// </summary>
+        private void BuildGUI()
+        {
+            Layout.Clear();
+
+            AudioSource source = InspectedObject as AudioSource;
+            if (source == null)
+                return;
+
+            audioClipField.OnChanged += x =>
+            {
+                AudioClip clip = Resources.Load<AudioClip>(x);
+
+                source.Clip = clip;
+                MarkAsModified();
+                ConfirmModify();
+            };
+
+            volumeField.OnChanged += x =>
+            {
+                source.Volume = x;
+                MarkAsModified();
+                ConfirmModify();
+            };
+
+            pitchField.OnChanged += x => { source.Pitch = x; MarkAsModified(); };
+            pitchField.OnConfirmed += ConfirmModify;
+            pitchField.OnFocusLost += ConfirmModify;
+
+            loopField.OnChanged += x =>
+            {
+                source.Loop = x;
+                MarkAsModified();
+                ConfirmModify();
+            };
+
+            priorityField.OnChanged += x => { source.Priority = (uint)x; MarkAsModified(); };
+            priorityField.OnConfirmed += ConfirmModify;
+            priorityField.OnFocusLost += ConfirmModify;
+
+            minDistanceField.OnChanged += x => { source.MinDistance = x; MarkAsModified(); };
+            minDistanceField.OnConfirmed += ConfirmModify;
+            minDistanceField.OnFocusLost += ConfirmModify;
+
+            attenuationField.OnChanged += x => { source.Attenuation = x; MarkAsModified(); };
+            attenuationField.OnConfirmed += ConfirmModify;
+            attenuationField.OnFocusLost += ConfirmModify;
+
+            Layout.AddElement(audioClipField);
+            Layout.AddElement(volumeField);
+            Layout.AddElement(pitchField);
+            Layout.AddElement(loopField);
+            Layout.AddElement(priorityField);
+            Layout.AddElement(minDistanceField);
+            Layout.AddElement(attenuationField);
+        }
+        
+        /// <summary>
+        /// Marks the contents of the inspector as modified.
+        /// </summary>
+        protected void MarkAsModified()
+        {
+            modifyState |= InspectableState.ModifyInProgress;
+        }
+
+        /// <summary>
+        /// Confirms any queued modifications.
+        /// </summary>
+        protected void ConfirmModify()
+        {
+            if (modifyState.HasFlag(InspectableState.ModifyInProgress))
+                modifyState |= InspectableState.Modified;
+        }
+    }
+
+    /** @} */
+}

+ 2 - 0
Source/MBansheeEditor/MBansheeEditor.csproj

@@ -41,6 +41,8 @@
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <Compile Include="Inspectors\AudioClipInspector.cs" />
     <Compile Include="Inspectors\AudioClipInspector.cs" />
+    <Compile Include="Inspectors\AudioListenerInspector.cs" />
+    <Compile Include="Inspectors\AudioSourceInspector.cs" />
     <Compile Include="Inspectors\PostProcessSettingsInspector.cs" />
     <Compile Include="Inspectors\PostProcessSettingsInspector.cs" />
     <Compile Include="Windows\AboutBox.cs" />
     <Compile Include="Windows\AboutBox.cs" />
     <Compile Include="Windows\BrowseDialog.cs" />
     <Compile Include="Windows\BrowseDialog.cs" />

+ 40 - 0
Source/MBansheeEditor/Window/MenuItems.cs

@@ -370,6 +370,46 @@ namespace BansheeEditor
             EditorApplication.SetSceneDirty();
             EditorApplication.SetSceneDirty();
         }
         }
 
 
+        /// <summary>
+        /// Adds an AudioListener component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Audio/Listener", 7031)]
+        private static void AddAudioListener()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+            {
+                so = UndoRedo.CreateSO("AudioListener", "New scene object");
+
+                Selection.SceneObject = so;
+                FocusOnHierarchyOrScene();
+            }
+
+            UndoRedo.RecordSO(so, false, "Added a AudioListener component");
+            so.AddComponent<AudioListener>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds an AudioSource component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Audio/Source", 7030)]
+        private static void AddAudioSource()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+            {
+                so = UndoRedo.CreateSO("AudioSource", "New scene object");
+
+                Selection.SceneObject = so;
+                FocusOnHierarchyOrScene();
+            }
+
+            UndoRedo.RecordSO(so, false, "Added a AudioSource component");
+            so.AddComponent<AudioSource>();
+            EditorApplication.SetSceneDirty();
+        }
+
         /// <summary>
         /// <summary>
         /// Creates a new empty scene object.
         /// Creates a new empty scene object.
         /// </summary>
         /// </summary>

+ 92 - 0
Source/MBansheeEngine/Audio/AudioListener.cs

@@ -0,0 +1,92 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+namespace BansheeEngine
+{
+    /** @addtogroup Audio
+     *  @{
+     */
+
+    /// <summary>
+    /// Represents a listener that hears audio sources. For spatial audio the volume and pitch of played audio is determined
+    /// by the distance, orientation and velocity differences between the source and the listener.
+    /// </summary>
+    public abstract class AudioListener : Component
+    {
+        internal NativeAudioListener native;
+
+        private Vector3 lastPosition;
+        private Vector3 velocity;
+
+        /// <summary>
+        /// Updates the transform of the internal listener representation from the transform of the component's scene
+        /// object.
+        /// </summary>
+        protected void UpdateTransform()
+        {
+            native.Position = SceneObject.Position;
+            native.Direction = SceneObject.Forward;
+            native.Up = SceneObject.Up;
+            native.Velocity = velocity;
+        }
+        
+        private void OnInitialize()
+        {
+            NotifyFlags = TransformChangedFlags.Transform;
+        }
+
+        private void OnUpdate()
+        {
+            Vector3 worldPos = SceneObject.Position;
+            velocity = (worldPos - lastPosition)/Time.FrameDelta;
+            lastPosition = worldPos;
+        }
+
+        private void OnEnable()
+        {
+            RestoreNative();
+        }
+
+        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();
+        }
+
+        /// <summary>
+        /// Destroys the internal listener representation.
+        /// </summary>
+        private void DestroyNative()
+        {
+            if (native != null)
+            {
+                native.Destroy();
+                native = null;
+            }
+        }
+
+        /// <summary>
+        /// Creates the internal representation of the listener and restores the values saved by the component.
+        /// </summary>
+        private void RestoreNative()
+        {
+            native = new NativeAudioListener();
+
+            UpdateTransform();
+        }
+    }
+
+    /** @} */
+}

+ 327 - 0
Source/MBansheeEngine/Audio/AudioSource.cs

@@ -0,0 +1,327 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+namespace BansheeEngine
+{
+    /** @addtogroup Audio
+     *  @{
+     */
+
+    /// <summary>
+    /// Valid states in which AudioSource can be in.
+    /// </summary>
+    public enum AudioSourceState // Note: Must match C++ enum AudioSourceState
+    {
+        /// <summary>
+        /// Source is currently playing.
+        /// </summary>
+        Playing,
+        /// <summary>
+        /// Source is currently paused (play will resume from paused point).
+        /// </summary>
+		Paused,
+        /// <summary>
+        /// Source is currently stopped (play will resume from start).
+        /// </summary>
+		Stopped
+    }
+
+    /// <summary>
+    /// 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.
+    /// </summary>
+    public abstract class AudioSource : Component
+    {
+        internal NativeAudioSource native;
+
+        [SerializeField]
+        internal SerializableData serializableData = new SerializableData();
+
+        private Vector3 lastPosition;
+        private Vector3 velocity;
+
+        /// <summary>
+        /// Audio clip that will be played.
+        /// </summary>
+        public AudioClip Clip
+        {
+            get { return serializableData.audioClip; }
+            set
+            {
+                if (serializableData.audioClip == value)
+                    return;
+
+                serializableData.audioClip = value;
+
+                if (native != null)
+                    native.Clip = value;
+            }
+        }
+
+        /// <summary>
+        /// Volume of the audio source, in [0, 1] range.
+        /// </summary>
+        public float Volume
+        {
+            get { return serializableData.volume; }
+            set
+            {
+                if (serializableData.volume == value)
+                    return;
+
+                serializableData.volume = value;
+
+                if (native != null)
+                    native.Volume = value;
+            }
+        }
+
+        /// <summary>
+        /// Pitch of the audio source.
+        /// </summary>
+        public float Pitch
+        {
+            get { return serializableData.pitch; }
+            set
+            {
+                if (serializableData.pitch == value)
+                    return;
+
+                serializableData.pitch = value;
+
+                if (native != null)
+                    native.Pitch = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines whether the audio clip should loop when it finishes playing.
+        /// </summary>
+        public bool Loop
+        {
+            get { return serializableData.loop; }
+            set
+            {
+                if (serializableData.loop == value)
+                    return;
+
+                serializableData.loop = value;
+
+                if (native != null)
+                    native.Loop = value;
+            }
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        public uint Priority
+        {
+            get { return serializableData.priority; }
+            set
+            {
+                if (serializableData.priority == value)
+                    return;
+
+                serializableData.priority = value;
+
+                if (native != null)
+                    native.Priority = value;
+            }
+        }
+
+        /// <summary>
+        /// 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.
+        /// </summary>
+        public float MinDistance
+        {
+            get { return serializableData.minDistance; }
+            set
+            {
+                if (serializableData.minDistance == value)
+                    return;
+
+                serializableData.minDistance = value;
+
+                if (native != null)
+                    native.MinDistance = value;
+            }
+        }
+
+        /// <summary>
+        /// Determines how quickly does audio volume drop off as the listener moves further from the source.
+        /// </summary>
+        public float Attenuation
+        {
+            get { return serializableData.attenuation; }
+            set
+            {
+                if (serializableData.attenuation == value)
+                    return;
+
+                serializableData.attenuation = value;
+
+                if (native != null)
+                    native.Attenuation = value;
+            }
+        }
+
+        /// <summary>
+        /// Playback position in seconds.
+        /// </summary>
+        public float Time
+        {
+            get
+            {
+                if (native != null)
+                    return native.Time;
+
+                return 0.0f;
+            }
+            set
+            {
+                if (native != null)
+                    native.Time = value;
+            }
+        }
+
+        /// <summary>
+        /// Returns the current state of the audio playback (playing/paused/stopped).
+        /// </summary>
+        public AudioSourceState State
+        {
+            get
+            {
+                if (native != null)
+                    return native.State;
+
+                return AudioSourceState.Stopped;
+            }
+        }
+
+        /// <summary>
+        /// Starts playing the currently assigned audio clip.
+        /// </summary>
+        public void Play()
+        {
+            if (native != null)
+                native.Play();
+        }
+
+        /// <summary>
+        /// Pauses audio playback.
+        /// </summary>
+        public void Pause()
+        {
+            if (native != null)
+                native.Pause();
+        }
+
+        /// <summary>
+        /// Stops audio playback, rewinding it to the start.
+        /// </summary>
+        public void Stop()
+        {
+            if (native != null)
+                native.Stop();
+        }
+
+        /// <summary>
+        /// Updates the transform of the internal source representation from the transform of the component's scene
+        /// object.
+        /// </summary>
+        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();
+        }
+
+        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();
+        }
+
+        /// <summary>
+        /// Destroys the internal source representation.
+        /// </summary>
+        private void DestroyNative()
+        {
+            if (native != null)
+            {
+                native.Destroy();
+                native = null;
+            }
+        }
+
+        /// <summary>
+        /// Creates the internal representation of the source and restores the values saved by the component.
+        /// </summary>
+        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();
+        }
+
+        /// <summary>
+        /// Holds all data the listener component needs to persist through serialization.
+        /// </summary>
+        [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;
+        }
+    }
+
+    /** @} */
+}

+ 70 - 0
Source/MBansheeEngine/Audio/Interop/NativeAudioListener.cs

@@ -0,0 +1,70 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+    /** @cond INTEROP */
+    /** @addtogroup Interop
+     *  @{
+     */
+
+    /// <summary>
+    /// Wrapper around the native AudioListener class.
+    /// <see cref="AudioListener"/>
+    /// </summary>
+    internal class NativeAudioListener : ScriptObject
+    {
+        public NativeAudioListener()
+        {
+            Internal_CreateInstance(this);
+        }
+
+        public Vector3 Position
+        {
+            set { Internal_SetPosition(mCachedPtr, ref value); }
+        }
+
+        public Vector3 Direction
+        {
+            set { Internal_SetDirection(mCachedPtr, ref value); }
+        }
+
+        public Vector3 Up
+        {
+            set { Internal_SetUp(mCachedPtr, ref value); }
+        }
+
+        public Vector3 Velocity
+        {
+            set { Internal_SetVelocity(mCachedPtr, ref value); }
+        }
+
+        public void Destroy()
+        {
+            Internal_Destroy(mCachedPtr);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstance(NativeAudioListener instance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Destroy(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetPosition(IntPtr thisPtr, ref Vector3 pos);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetDirection(IntPtr thisPtr, ref Vector3 direction);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetUp(IntPtr thisPtr, ref Vector3 up);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetVelocity(IntPtr thisPtr, ref Vector3 velocity);
+    }
+
+    /** @} */
+    /** @endcond */
+}

+ 161 - 0
Source/MBansheeEngine/Audio/Interop/NativeAudioSource.cs

@@ -0,0 +1,161 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+    /** @cond INTEROP */
+    /** @addtogroup Interop
+     *  @{
+     */
+
+    /// <summary>
+    /// Wrapper around the native AudioSource class.
+    /// <see cref="AudioSource"/>
+    /// </summary>
+    internal class NativeAudioSource : ScriptObject
+    {
+        public NativeAudioSource()
+        {
+            Internal_CreateInstance(this);
+        }
+
+        public Vector3 Position
+        {
+            set { Internal_SetPosition(mCachedPtr, ref value); }
+        }
+
+        public Vector3 Velocity
+        {
+            set { Internal_SetVelocity(mCachedPtr, ref value); }
+        }
+
+        public AudioClip Clip
+        {
+            set
+            {
+                IntPtr clipPtr = IntPtr.Zero;
+                if (value != null)
+                    clipPtr = value.GetCachedPtr();
+
+                Internal_SetClip(mCachedPtr, clipPtr);
+            }
+        }
+
+        public float Volume
+        {
+            set { Internal_SetVolume(mCachedPtr, value); }
+        }
+
+        public float Pitch
+        {
+            set { Internal_SetPitch(mCachedPtr, value); }
+        }
+
+        public bool Loop
+        {
+            set { Internal_SetIsLooping(mCachedPtr, value); }
+        }
+
+        public uint Priority
+        {
+            set { Internal_SetPriority(mCachedPtr, value); }
+        }
+
+        public float MinDistance
+        {
+            set { Internal_SetMinDistance(mCachedPtr, value); }
+        }
+
+        public float Attenuation
+        {
+            set { Internal_SetAttenuation(mCachedPtr, value); }
+        }
+
+        public float Time
+        {
+            get { return Internal_GetTime(mCachedPtr); }
+            set { Internal_SetTime(mCachedPtr, value); }
+        }
+
+        public AudioSourceState State
+        {
+            get { return (AudioSourceState)Internal_GetState(mCachedPtr); }
+        }
+
+        public void Play()
+        {
+            Internal_Play(mCachedPtr);
+        }
+
+        public void Pause()
+        {
+            Internal_Pause(mCachedPtr);
+        }
+
+        public void Stop()
+        {
+            Internal_Stop(mCachedPtr);
+        }
+
+        public void Destroy()
+        {
+            Internal_Destroy(mCachedPtr);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstance(NativeAudioSource instance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Destroy(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetPosition(IntPtr thisPtr, ref Vector3 pos);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetVelocity(IntPtr thisPtr, ref Vector3 velocity);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetClip(IntPtr thisPtr, IntPtr clip);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetVolume(IntPtr thisPtr, float volume);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetPitch(IntPtr thisPtr, float pitch);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetIsLooping(IntPtr thisPtr, bool loop);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetPriority(IntPtr thisPtr, uint priority);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetMinDistance(IntPtr thisPtr, float distance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetAttenuation(IntPtr thisPtr, float attenuation);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetTime(IntPtr thisPtr, float position);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern float Internal_GetTime(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Play(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Pause(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Stop(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern int Internal_GetState(IntPtr thisPtr);
+    }
+
+    /** @} */
+    /** @endcond */
+}

+ 4 - 0
Source/MBansheeEngine/MBansheeEngine.csproj

@@ -45,6 +45,10 @@
   <ItemGroup>
   <ItemGroup>
     <Compile Include="Audio\Audio.cs" />
     <Compile Include="Audio\Audio.cs" />
     <Compile Include="Audio\AudioClip.cs" />
     <Compile Include="Audio\AudioClip.cs" />
+    <Compile Include="Audio\AudioListener.cs" />
+    <Compile Include="Audio\AudioSource.cs" />
+    <Compile Include="Audio\Interop\NativeAudioListener.cs" />
+    <Compile Include="Audio\Interop\NativeAudioSource.cs" />
     <Compile Include="Rendering\PostProcessSettings.cs" />
     <Compile Include="Rendering\PostProcessSettings.cs" />
     <Compile Include="Utility\AsyncOp.cs" />
     <Compile Include="Utility\AsyncOp.cs" />
     <Compile Include="Math\Bounds.cs" />
     <Compile Include="Math\Bounds.cs" />

+ 2 - 1
Source/SBansheeEngine/Include/BsScriptAudioSource.h

@@ -37,10 +37,11 @@ namespace BansheeEngine
 		static void internal_SetPriority(ScriptAudioSource* thisPtr, UINT32 priority);
 		static void internal_SetPriority(ScriptAudioSource* thisPtr, UINT32 priority);
 		static void internal_SetMinDistance(ScriptAudioSource* thisPtr, float distance);
 		static void internal_SetMinDistance(ScriptAudioSource* thisPtr, float distance);
 		static void internal_SetAttenuation(ScriptAudioSource* thisPtr, float attenuation);
 		static void internal_SetAttenuation(ScriptAudioSource* thisPtr, float attenuation);
+		static void internal_SetTime(ScriptAudioSource* thisPtr, float position);
+		static float internal_GetTime(ScriptAudioSource* thisPtr);
 		static void internal_Play(ScriptAudioSource* thisPtr);
 		static void internal_Play(ScriptAudioSource* thisPtr);
 		static void internal_Pause(ScriptAudioSource* thisPtr);
 		static void internal_Pause(ScriptAudioSource* thisPtr);
 		static void internal_Stop(ScriptAudioSource* thisPtr);
 		static void internal_Stop(ScriptAudioSource* thisPtr);
-		static void internal_Seek(ScriptAudioSource* thisPtr, float position);
 		static UINT32 internal_GetState(ScriptAudioSource* thisPtr);
 		static UINT32 internal_GetState(ScriptAudioSource* thisPtr);
 	};
 	};
 
 

+ 8 - 2
Source/SBansheeEngine/Source/BsScriptAudioSource.cpp

@@ -31,7 +31,8 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_Play", &ScriptAudioSource::internal_Play);
 		metaData.scriptClass->addInternalCall("Internal_Play", &ScriptAudioSource::internal_Play);
 		metaData.scriptClass->addInternalCall("Internal_Pause", &ScriptAudioSource::internal_Pause);
 		metaData.scriptClass->addInternalCall("Internal_Pause", &ScriptAudioSource::internal_Pause);
 		metaData.scriptClass->addInternalCall("Internal_Stop", &ScriptAudioSource::internal_Stop);
 		metaData.scriptClass->addInternalCall("Internal_Stop", &ScriptAudioSource::internal_Stop);
-		metaData.scriptClass->addInternalCall("Internal_Seek", &ScriptAudioSource::internal_Seek);
+		metaData.scriptClass->addInternalCall("Internal_SetTime", &ScriptAudioSource::internal_SetTime);
+		metaData.scriptClass->addInternalCall("Internal_GetTime", &ScriptAudioSource::internal_GetTime);
 		metaData.scriptClass->addInternalCall("Internal_GetState", &ScriptAudioSource::internal_GetState);
 		metaData.scriptClass->addInternalCall("Internal_GetState", &ScriptAudioSource::internal_GetState);
 	}
 	}
 
 
@@ -110,11 +111,16 @@ namespace BansheeEngine
 		thisPtr->mSource->stop();
 		thisPtr->mSource->stop();
 	}
 	}
 
 
-	void ScriptAudioSource::internal_Seek(ScriptAudioSource* thisPtr, float position)
+	void ScriptAudioSource::internal_SetTime(ScriptAudioSource* thisPtr, float position)
 	{
 	{
 		thisPtr->mSource->seek(position);
 		thisPtr->mSource->seek(position);
 	}
 	}
 
 
+	float ScriptAudioSource::internal_GetTime(ScriptAudioSource* thisPtr)
+	{
+		return thisPtr->mSource->tell();
+	}
+
 	UINT32 ScriptAudioSource::internal_GetState(ScriptAudioSource* thisPtr)
 	UINT32 ScriptAudioSource::internal_GetState(ScriptAudioSource* thisPtr)
 	{
 	{
 		return (UINT32)thisPtr->mSource->getState();
 		return (UINT32)thisPtr->mSource->getState();