3D Audio GSoC:
authorJoerg Mueller <nexyon@gmail.com>
Tue, 12 Jul 2011 13:11:00 +0000 (13:11 +0000)
committerJoerg Mueller <nexyon@gmail.com>
Tue, 12 Jul 2011 13:11:00 +0000 (13:11 +0000)
Software 3D Audio implementation.

intern/audaspace/OpenAL/AUD_OpenALDevice.cpp
intern/audaspace/intern/AUD_3DMath.h
intern/audaspace/intern/AUD_ChannelMapperReader.cpp
intern/audaspace/intern/AUD_ChannelMapperReader.h
intern/audaspace/intern/AUD_SoftwareDevice.cpp
intern/audaspace/intern/AUD_SoftwareDevice.h

index c36f29aa179b5f683ff4ba6d77a93c3c8e3f9bb9..3b306d89d7b7d3dd063021061378d88e99dec8f8 100644 (file)
@@ -492,10 +492,10 @@ bool AUD_OpenALDevice::AUD_OpenALHandle::setSourceOrientation(const AUD_Quaterni
 
 bool AUD_OpenALDevice::AUD_OpenALHandle::isRelative()
 {
-       int result = std::numeric_limits<float>::quiet_NaN();
+       int result;
 
        if(!m_status)
-               return result;
+               return false;
 
        m_device->lock();
 
index fc095ebaca7cb32c9c345204d4bdbd0f80115752..3a6abf811ce2b739cc473ce143ef545ec2b4cf40 100644 (file)
 #ifndef AUD_3DMATH
 #define AUD_3DMATH
 
-class AUD_Quaternion
+#include <cmath>
+
+class AUD_Vector3
 {
 private:
        union
        {
-               float m_v[4];
+               float m_v[3];
                struct
                {
-                       float m_w;
                        float m_x;
                        float m_y;
                        float m_z;
@@ -49,28 +50,18 @@ private:
 
 public:
        /**
-        * Creates a new quaternion.
-        * \param w The w component.
+        * Creates a new 3 dimensional vector.
         * \param x The x component.
         * \param y The y component.
         * \param z The z component.
         */
-       inline AUD_Quaternion(float w, float x, float y, float z) :
-               m_w(w), m_x(x), m_y(y), m_z(z)
-       {
-       }
-
-       /**
-        * Retrieves the w component of the quarternion.
-        * \return The w component.
-        */
-       inline const float& w() const
+       inline AUD_Vector3(float x = 0, float y = 0, float z = 0) :
+               m_x(x), m_y(y), m_z(z)
        {
-               return m_w;
        }
 
        /**
-        * Retrieves the x component of the quarternion.
+        * Retrieves the x component of the vector.
         * \return The x component.
         */
        inline const float& x() const
@@ -79,7 +70,7 @@ public:
        }
 
        /**
-        * Retrieves the y component of the quarternion.
+        * Retrieves the y component of the vector.
         * \return The y component.
         */
        inline const float& y() const
@@ -88,7 +79,7 @@ public:
        }
 
        /**
-        * Retrieves the z component of the quarternion.
+        * Retrieves the z component of the vector.
         * \return The z component.
         */
        inline const float& z() const
@@ -98,34 +89,80 @@ public:
 
        /**
         * Retrieves the components of the vector.
-        * \param destination Where the 4 float values should be saved to.
+        * \param destination Where the 3 float values should be saved to.
         */
        inline void get(float* destination) const
        {
-               destination[0] = m_w;
-               destination[1] = m_x;
-               destination[2] = m_y;
-               destination[3] = m_z;
+               destination[0] = m_x;
+               destination[1] = m_y;
+               destination[2] = m_z;
        }
 
        /**
         * Retrieves the components of the vector.
-        * \return The components as float[4].
+        * \return The components as float[3].
         */
        inline const float* get() const
        {
                return m_v;
        }
+
+       /**
+        * Retrieves the length of the vector.
+        * \return The length of the vector.
+        */
+       inline float length() const
+       {
+               return sqrt(m_x*m_x + m_y*m_y + m_z*m_z);
+       }
+
+       inline AUD_Vector3 cross(const AUD_Vector3& op) const
+       {
+               return AUD_Vector3(m_y * op.m_z - m_z * op.m_y,
+                                                  m_z * op.m_x - m_x * op.m_z,
+                                                  m_x * op.m_y - m_y * op.m_x);
+       }
+
+       /**
+        * Retrieves the dot product.
+        * \param op The second operand.
+        * \return The dot product of the two vectors.
+        */
+       inline float operator*(const AUD_Vector3& op) const
+       {
+               return m_x * op.m_x + m_y * op.m_y + m_z * op.m_z;
+       }
+
+       inline AUD_Vector3 operator*(const float& op) const
+       {
+               return AUD_Vector3(m_x * op, m_y * op, m_z * op);
+       }
+
+       inline AUD_Vector3 operator+(const AUD_Vector3& op) const
+       {
+               return AUD_Vector3(m_x + op.m_x, m_y + op.m_y, m_z + op.m_z);
+       }
+
+       inline AUD_Vector3 operator-(const AUD_Vector3& op) const
+       {
+               return AUD_Vector3(m_x - op.m_x, m_y - op.m_y, m_z - op.m_z);
+       }
+
+       inline AUD_Vector3 operator-() const
+       {
+               return AUD_Vector3(-m_x, -m_y, -m_z);
+       }
 };
 
-class AUD_Vector3
+class AUD_Quaternion
 {
 private:
        union
        {
-               float m_v[3];
+               float m_v[4];
                struct
                {
+                       float m_w;
                        float m_x;
                        float m_y;
                        float m_z;
@@ -134,18 +171,28 @@ private:
 
 public:
        /**
-        * Creates a new 3 dimensional vector.
+        * Creates a new quaternion.
+        * \param w The w component.
         * \param x The x component.
         * \param y The y component.
         * \param z The z component.
         */
-       inline AUD_Vector3(float x, float y, float z) :
-               m_x(x), m_y(y), m_z(z)
+       inline AUD_Quaternion(float w = 1, float x = 0, float y = 0, float z = 0) :
+               m_w(w), m_x(x), m_y(y), m_z(z)
        {
        }
 
        /**
-        * Retrieves the x component of the vector.
+        * Retrieves the w component of the quarternion.
+        * \return The w component.
+        */
+       inline const float& w() const
+       {
+               return m_w;
+       }
+
+       /**
+        * Retrieves the x component of the quarternion.
         * \return The x component.
         */
        inline const float& x() const
@@ -154,7 +201,7 @@ public:
        }
 
        /**
-        * Retrieves the y component of the vector.
+        * Retrieves the y component of the quarternion.
         * \return The y component.
         */
        inline const float& y() const
@@ -163,7 +210,7 @@ public:
        }
 
        /**
-        * Retrieves the z component of the vector.
+        * Retrieves the z component of the quarternion.
         * \return The z component.
         */
        inline const float& z() const
@@ -173,23 +220,38 @@ public:
 
        /**
         * Retrieves the components of the vector.
-        * \param destination Where the 3 float values should be saved to.
+        * \param destination Where the 4 float values should be saved to.
         */
        inline void get(float* destination) const
        {
-               destination[0] = m_x;
-               destination[1] = m_y;
-               destination[2] = m_z;
+               destination[0] = m_w;
+               destination[1] = m_x;
+               destination[2] = m_y;
+               destination[3] = m_z;
        }
 
        /**
         * Retrieves the components of the vector.
-        * \return The components as float[3].
+        * \return The components as float[4].
         */
        inline const float* get() const
        {
                return m_v;
        }
+
+       inline AUD_Vector3 getLookAt() const
+       {
+               return AUD_Vector3(-2 * (m_w * m_y + m_x * m_z),
+                                                       2 * (m_x * m_w - m_z * m_y),
+                                                       2 * (m_x * m_x + m_y * m_y) - 1);
+       }
+
+       inline AUD_Vector3 getUp() const
+       {
+               return AUD_Vector3(2 * (m_x * m_y - m_w * m_z),
+                                                       1 - 2 * (m_x * m_x + m_z * m_z),
+                                                       2 * (m_w * m_x + m_y * m_z));
+       }
 };
 
 #endif //AUD_3DMATH
index 5b937a302420bfa7a191a0f468099b9b3129fdee..56c45da3fe4a18644107e82036e5097c09d17f98 100644 (file)
@@ -43,7 +43,7 @@
 AUD_ChannelMapperReader::AUD_ChannelMapperReader(AUD_Reference<AUD_IReader> reader,
                                                                                                 AUD_Channels channels) :
                AUD_EffectReader(reader), m_target_channels(channels),
-       m_source_channels(AUD_CHANNELS_INVALID), m_mapping(0)
+       m_source_channels(AUD_CHANNELS_INVALID), m_mapping(0), m_map_size(0), m_mono_angle(0)
 {
 }
 
@@ -58,6 +58,13 @@ void AUD_ChannelMapperReader::setChannels(AUD_Channels channels)
        calculateMapping();
 }
 
+void AUD_ChannelMapperReader::setMonoAngle(float angle)
+{
+       m_mono_angle = angle;
+       if(m_source_channels == AUD_CHANNELS_MONO)
+               calculateMapping();
+}
+
 float AUD_ChannelMapperReader::angleDistance(float alpha, float beta)
 {
        alpha = fabs(alpha - beta);
@@ -68,10 +75,19 @@ float AUD_ChannelMapperReader::angleDistance(float alpha, float beta)
        return alpha;
 }
 
+#include <iostream>
+
 void AUD_ChannelMapperReader::calculateMapping()
 {
-       delete[] m_mapping;
-       m_mapping = new float[m_source_channels * m_target_channels];
+       if(m_map_size < m_source_channels * m_target_channels)
+       {
+               delete[] m_mapping;
+               m_mapping = new float[m_source_channels * m_target_channels];
+               m_map_size = m_source_channels * m_target_channels;
+       }
+
+       for(int i = 0; i < m_source_channels * m_target_channels; i++)
+               m_mapping[i] = 0;
 
        const AUD_Channel* source_channels = CHANNEL_MAPS[m_source_channels - 1];
        const AUD_Channel* target_channels = CHANNEL_MAPS[m_target_channels - 1];
@@ -90,6 +106,9 @@ void AUD_ChannelMapperReader::calculateMapping()
        const float* source_angles = CHANNEL_ANGLES[m_source_channels - 1];
        const float* target_angles = CHANNEL_ANGLES[m_target_channels - 1];
 
+       if(m_source_channels == AUD_CHANNELS_MONO)
+               source_angles = &m_mono_angle;
+
        int channel_min1, channel_min2;
        float angle_min1, angle_min2, angle;
 
@@ -124,17 +143,26 @@ void AUD_ChannelMapperReader::calculateMapping()
                        }
                }
 
-               if(channel_min2 == -1)
+               angle = angle_min1 + angle_min2;
+               if(channel_min2 == -1 || angle == 0)
                {
                        m_mapping[channel_min1 * m_source_channels + i] = 1;
                }
                else
                {
-                       angle = angle_min1 + angle_min2;
                        m_mapping[channel_min1 * m_source_channels + i] = cos(M_PI_2 * angle_min1 / angle);
                        m_mapping[channel_min2 * m_source_channels + i] = cos(M_PI_2 * angle_min2 / angle);
                }
        }
+
+       /* AUD_XXX for(int i = 0; i < m_source_channels; i++)
+       {
+               for(int j = 0; j < m_target_channels; j++)
+               {
+                       std::cout << m_mapping[i * m_source_channels + j] << " ";
+               }
+               std::cout << std::endl;
+       }*/
 }
 
 AUD_Specs AUD_ChannelMapperReader::getSpecs() const
index 3da34ed85cefc2ecd68e8640f3bc210d4566aab4..fa035531763a12eb988bf891f66db10761dba42e 100644 (file)
@@ -62,6 +62,16 @@ private:
         */
        float* m_mapping;
 
+       /**
+        * The size of the mapping.
+        */
+       int m_map_size;
+
+       /**
+        * The mono source angle.
+        */
+       float m_mono_angle;
+
        static const AUD_Channel MONO_MAP[];
        static const AUD_Channel STEREO_MAP[];
        static const AUD_Channel STEREO_LFE_MAP[];
@@ -111,6 +121,8 @@ public:
 
        void setChannels(AUD_Channels channels);
 
+       void setMonoAngle(float angle);
+
        virtual AUD_Specs getSpecs() const;
        virtual void read(int& length, bool& eos, sample_t* buffer);
 };
index ba5f121f61758e51a125172f0dee9d1007a2e49c..c19f65afc6de18bb4daccd88f529c2111d7197d4 100644 (file)
 #else
 #include "AUD_LinearResampleReader.h"
 #endif
-#include "AUD_ChannelMapperReader.h"
 
 #include <cstring>
+#include <cmath>
 #include <limits>
 
-AUD_SoftwareDevice::AUD_SoftwareHandle::AUD_SoftwareHandle(AUD_SoftwareDevice* device, AUD_Reference<AUD_IReader> reader, AUD_Reference<AUD_PitchReader> pitch, bool keep) :
-       m_reader(reader), m_pitch(pitch), m_keep(keep), m_volume(1.0f), m_loopcount(0),
-       m_stop(NULL), m_stop_data(NULL), m_status(AUD_STATUS_PLAYING), m_device(device)
+typedef enum
 {
+       AUD_RENDER_DISTANCE = 0x01,
+       AUD_RENDER_DOPPLER = 0x02,
+       AUD_RENDER_CONE = 0x04,
+       AUD_RENDER_VOLUME = 0x08
+} AUD_RenderFlags;
+
+#define AUD_PITCH_MAX 10
+
+/******************************************************************************/
+/********************** AUD_SoftwareHandle Handle Code ************************/
+/******************************************************************************/
+
+AUD_SoftwareDevice::AUD_SoftwareHandle::AUD_SoftwareHandle(AUD_SoftwareDevice* device, AUD_Reference<AUD_IReader> reader, AUD_Reference<AUD_PitchReader> pitch, AUD_Reference<AUD_ChannelMapperReader> mapper, bool keep) :
+       m_reader(reader), m_pitch(pitch), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_volume(1.0f), m_loopcount(0),
+       m_relative(false), m_volume_max(1.0f), m_volume_min(0), m_distance_max(std::numeric_limits<float>::max()),
+       m_distance_reference(1.0f), m_attenuation(1.0f), m_cone_angle_outer(M_PI), m_cone_angle_inner(M_PI), m_cone_volume_outer(0),
+       m_flags(AUD_RENDER_CONE), m_stop(NULL), m_stop_data(NULL), m_status(AUD_STATUS_PLAYING), m_device(device)
+{
+}
+
+#include <iostream>
+
+void AUD_SoftwareDevice::AUD_SoftwareHandle::update()
+{
+       int flags = 0;
+
+       AUD_Vector3 SL;
+       if(m_relative)
+               SL = m_location;
+       else
+               SL = m_device->m_location - m_location;
+       float distance = SL * SL;
+
+       if(distance > 0)
+               distance = sqrt(distance);
+       else
+               flags |= AUD_RENDER_DOPPLER | AUD_RENDER_DISTANCE;
+
+       if(m_pitch->getSpecs().channels != AUD_CHANNELS_MONO)
+       {
+               m_volume = m_user_volume;
+               m_pitch->setPitch(m_user_pitch);
+               return;
+       }
+
+       flags = ~(flags | m_flags | m_device->m_flags);
+
+       // Doppler and Pitch
+
+       if(flags & AUD_RENDER_DOPPLER)
+       {
+               float vls;
+               if(m_relative)
+                       vls = 0;
+               else
+                       vls = SL * m_device->m_velocity / distance;
+               float vss = SL * m_velocity / distance;
+               float max = m_device->m_speed_of_sound / m_device->m_doppler_factor;
+               if(vss >= max)
+               {
+                       m_pitch->setPitch(AUD_PITCH_MAX);
+               }
+               else
+               {
+                       if(vls > max)
+                               vls = max;
+
+                       m_pitch->setPitch((m_device->m_speed_of_sound - m_device->m_doppler_factor * vls) / (m_device->m_speed_of_sound - m_device->m_doppler_factor * vss) * m_user_pitch);
+               }
+       }
+       else
+               m_pitch->setPitch(m_user_pitch);
+
+       if(flags & AUD_RENDER_VOLUME)
+       {
+               // Distance
+
+               if(flags & AUD_RENDER_DISTANCE)
+               {
+                       if(m_device->m_distance_model == AUD_DISTANCE_MODEL_INVERSE_CLAMPED || m_device->m_distance_model == AUD_DISTANCE_MODEL_LINEAR_CLAMPED || m_device->m_distance_model == AUD_DISTANCE_MODEL_EXPONENT_CLAMPED)
+                       {
+                               distance = AUD_MAX(AUD_MIN(m_distance_max, distance), m_distance_reference);
+                       }
+
+                       switch(m_device->m_distance_model)
+                       {
+                       case AUD_DISTANCE_MODEL_INVERSE:
+                       case AUD_DISTANCE_MODEL_INVERSE_CLAMPED:
+                               m_volume = m_distance_reference / (m_distance_reference + m_attenuation * (distance - m_distance_reference));
+                               break;
+                       case AUD_DISTANCE_MODEL_LINEAR:
+                       case AUD_DISTANCE_MODEL_LINEAR_CLAMPED:
+                       {
+                               float temp = m_distance_max - m_distance_reference;
+                               if(temp == 0)
+                               {
+                                       if(distance > m_distance_reference)
+                                               m_volume = 0.0f;
+                                       else
+                                               m_volume = 1.0f;
+                               }
+                               else
+                                       m_volume = 1.0f - m_attenuation * (distance - m_distance_reference) / (m_distance_max - m_distance_reference);
+                               break;
+                       }
+                       case AUD_DISTANCE_MODEL_EXPONENT:
+                       case AUD_DISTANCE_MODEL_EXPONENT_CLAMPED:
+                               if(m_distance_reference == 0)
+                                       m_volume = 0;
+                               else
+                                       m_volume = pow(distance / m_distance_reference, -m_attenuation);
+                               break;
+                       default:
+                               m_volume = 1.0f;
+                       }
+               }
+               else
+                       m_volume = 1.0f;
+
+               // Cone
+
+               if(flags & AUD_RENDER_CONE)
+               {
+                       AUD_Vector3 SZ = m_orientation.getLookAt();
+
+                       float phi = acos(SZ * SL / (SZ.length() * SL.length()));
+                       float t = (phi - m_cone_angle_inner)/(m_cone_angle_outer - m_cone_angle_inner);
+
+                       if(t > 0)
+                       {
+                               if(t > 1)
+                                       m_volume *= m_cone_volume_outer;
+                               else
+                                       m_volume *= 1 + t * (m_cone_volume_outer - 1);
+                       }
+               }
+
+               // Volume
+
+               m_volume *= m_user_volume;
+       }
+
+       // 3D Cue
+
+       AUD_Quaternion orientation;
+
+       if(!m_relative)
+               orientation = m_device->m_orientation;
+
+       AUD_Vector3 Z = orientation.getLookAt();
+       AUD_Vector3 N = orientation.getUp();
+       AUD_Vector3 A = N * ((SL * N) / (N * N)) - SL;
+
+       float Asquare = A * A;
+
+       if(Asquare > 0)
+       {
+               float phi = acos(Z * A/ (Z.length() * sqrt(Asquare)));
+               if(N.cross(Z) * A > 0)
+                       phi = -phi;
+
+               m_mapper->setMonoAngle(phi);
+       }
+       else
+               m_mapper->setMonoAngle(0);
 }
 
 bool AUD_SoftwareDevice::AUD_SoftwareHandle::pause()
@@ -177,25 +340,36 @@ AUD_Status AUD_SoftwareDevice::AUD_SoftwareHandle::getStatus()
 
 float AUD_SoftwareDevice::AUD_SoftwareHandle::getVolume()
 {
-       return m_volume;
+       return m_user_volume;
 }
 
 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setVolume(float volume)
 {
        if(!m_status)
                return false;
-       m_volume = volume;
+       m_user_volume = volume;
+
+       if(volume == 0)
+       {
+               m_volume = volume;
+               m_flags |= AUD_RENDER_VOLUME;
+       }
+       else
+               m_flags &= ~AUD_RENDER_VOLUME;
+
        return true;
 }
 
 float AUD_SoftwareDevice::AUD_SoftwareHandle::getPitch()
 {
-       return m_pitch->getPitch();
+       return m_user_pitch;
 }
 
 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setPitch(float pitch)
 {
-       m_pitch->setPitch(pitch);
+       if(!m_status)
+               return false;
+       m_user_pitch = pitch;
        return true;
 }
 
@@ -231,19 +405,249 @@ bool AUD_SoftwareDevice::AUD_SoftwareHandle::setStopCallback(stopCallback callba
 
 
 
+/******************************************************************************/
+/******************** AUD_SoftwareHandle 3DHandle Code ************************/
+/******************************************************************************/
+
+AUD_Vector3 AUD_SoftwareDevice::AUD_SoftwareHandle::getSourceLocation()
+{
+       if(!m_status)
+               return AUD_Vector3();
+
+       return m_location;
+}
+
+bool AUD_SoftwareDevice::AUD_SoftwareHandle::setSourceLocation(const AUD_Vector3& location)
+{
+       if(!m_status)
+               return false;
+
+       m_location = location;
+
+       return true;
+}
+
+AUD_Vector3 AUD_SoftwareDevice::AUD_SoftwareHandle::getSourceVelocity()
+{
+       if(!m_status)
+               return AUD_Vector3();
+
+       return m_velocity;
+}
+
+bool AUD_SoftwareDevice::AUD_SoftwareHandle::setSourceVelocity(const AUD_Vector3& velocity)
+{
+       if(!m_status)
+               return false;
+
+       m_velocity = velocity;
+
+       return true;
+}
+
+AUD_Quaternion AUD_SoftwareDevice::AUD_SoftwareHandle::getSourceOrientation()
+{
+       if(!m_status)
+               return AUD_Quaternion();
+
+       return m_orientation;
+}
+
+bool AUD_SoftwareDevice::AUD_SoftwareHandle::setSourceOrientation(const AUD_Quaternion& orientation)
+{
+       if(!m_status)
+               return false;
+
+       m_orientation = orientation;
+
+       return true;
+}
+
+bool AUD_SoftwareDevice::AUD_SoftwareHandle::isRelative()
+{
+       if(!m_status)
+               return false;
+
+       return m_relative;
+}
+
+bool AUD_SoftwareDevice::AUD_SoftwareHandle::setRelative(bool relative)
+{
+       if(!m_status)
+               return false;
+
+       m_relative = relative;
+
+       return true;
+}
 
+float AUD_SoftwareDevice::AUD_SoftwareHandle::getVolumeMaximum()
+{
+       if(!m_status)
+               return std::numeric_limits<float>::quiet_NaN();
 
+       return m_volume_max;
+}
 
+bool AUD_SoftwareDevice::AUD_SoftwareHandle::setVolumeMaximum(float volume)
+{
+       if(!m_status)
+               return false;
 
+       m_volume_max = volume;
 
+       return true;
+}
 
+float AUD_SoftwareDevice::AUD_SoftwareHandle::getVolumeMinimum()
+{
+       if(!m_status)
+               return std::numeric_limits<float>::quiet_NaN();;
 
+       return m_volume_min;
+}
+
+bool AUD_SoftwareDevice::AUD_SoftwareHandle::setVolumeMinimum(float volume)
+{
+       if(!m_status)
+               return false;
+
+       m_volume_min = volume;
+
+       return true;
+}
+
+float AUD_SoftwareDevice::AUD_SoftwareHandle::getDistanceMaximum()
+{
+       if(!m_status)
+               return std::numeric_limits<float>::quiet_NaN();
+
+       return m_distance_max;
+}
+
+bool AUD_SoftwareDevice::AUD_SoftwareHandle::setDistanceMaximum(float distance)
+{
+       if(!m_status)
+               return false;
+
+       m_distance_max = distance;
+
+       return true;
+}
+
+float AUD_SoftwareDevice::AUD_SoftwareHandle::getDistanceReference()
+{
+       if(!m_status)
+               return std::numeric_limits<float>::quiet_NaN();
+
+       return m_distance_reference;
+}
+
+bool AUD_SoftwareDevice::AUD_SoftwareHandle::setDistanceReference(float distance)
+{
+       if(!m_status)
+               return false;
+
+       m_distance_reference = distance;
+
+       return true;
+}
+
+float AUD_SoftwareDevice::AUD_SoftwareHandle::getAttenuation()
+{
+       if(!m_status)
+               return std::numeric_limits<float>::quiet_NaN();
+
+       return m_attenuation;
+}
+
+bool AUD_SoftwareDevice::AUD_SoftwareHandle::setAttenuation(float factor)
+{
+       if(!m_status)
+               return false;
+
+       m_attenuation = factor;
+
+       if(factor == 0)
+               m_flags |= AUD_RENDER_DISTANCE;
+       else
+               m_flags &= ~AUD_RENDER_DISTANCE;
+
+       return true;
+}
+
+float AUD_SoftwareDevice::AUD_SoftwareHandle::getConeAngleOuter()
+{
+       if(!m_status)
+               return std::numeric_limits<float>::quiet_NaN();
+
+       return m_cone_angle_outer * 360.0f / M_PI;
+}
+
+bool AUD_SoftwareDevice::AUD_SoftwareHandle::setConeAngleOuter(float angle)
+{
+       if(!m_status)
+               return false;
+
+       m_cone_angle_outer = angle * M_PI / 360.0f;
+
+       return true;
+}
+
+float AUD_SoftwareDevice::AUD_SoftwareHandle::getConeAngleInner()
+{
+       if(!m_status)
+               return std::numeric_limits<float>::quiet_NaN();
+
+       return m_cone_angle_inner * 360.0f / M_PI;
+}
+
+bool AUD_SoftwareDevice::AUD_SoftwareHandle::setConeAngleInner(float angle)
+{
+       if(!m_status)
+               return false;
+
+       if(angle >= 360)
+               m_flags |= AUD_RENDER_CONE;
+       else
+               m_flags &= ~AUD_RENDER_CONE;
+
+       m_cone_angle_inner = angle * M_PI / 360.0f;
+
+       return true;
+}
+
+float AUD_SoftwareDevice::AUD_SoftwareHandle::getConeVolumeOuter()
+{
+       if(!m_status)
+               return std::numeric_limits<float>::quiet_NaN();;
+
+       return m_cone_volume_outer;
+}
+
+bool AUD_SoftwareDevice::AUD_SoftwareHandle::setConeVolumeOuter(float volume)
+{
+       if(!m_status)
+               return false;
+
+       m_cone_volume_outer = volume;
+
+       return true;
+}
+
+/******************************************************************************/
+/**************************** IDevice Code ************************************/
+/******************************************************************************/
 
 void AUD_SoftwareDevice::create()
 {
        m_playback = false;
        m_volume = 1.0f;
        m_mixer = new AUD_Mixer(m_specs);
+       m_speed_of_sound = 343.0f;
+       m_doppler_factor = 1.0f;
+       m_distance_model = AUD_DISTANCE_MODEL_INVERSE_CLAMPED;
+       m_flags = 0;
 
        pthread_mutexattr_t attr;
        pthread_mutexattr_init(&attr);
@@ -297,6 +701,9 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length)
                        pos = 0;
                        len = length;
 
+                       // update 3D Info
+                       sound->update();
+
                        sound->m_reader->read(len, eos, buf);
 
                        // in case of looping
@@ -370,13 +777,14 @@ AUD_Reference<AUD_IHandle> AUD_SoftwareDevice::play(AUD_Reference<AUD_IReader> r
        #endif
 
        // rechannel
-       reader = new AUD_ChannelMapperReader(reader, m_specs.channels);
+       AUD_Reference<AUD_ChannelMapperReader> mapper = new AUD_ChannelMapperReader(reader, m_specs.channels);
+       reader = AUD_Reference<AUD_IReader>(mapper);
 
        if(reader.isNull())
                return NULL;
 
        // play sound
-       AUD_Reference<AUD_SoftwareDevice::AUD_SoftwareHandle> sound = new AUD_SoftwareDevice::AUD_SoftwareHandle(this, reader, pitch, keep);
+       AUD_Reference<AUD_SoftwareDevice::AUD_SoftwareHandle> sound = new AUD_SoftwareDevice::AUD_SoftwareHandle(this, reader, pitch, mapper, keep);
 
        lock();
        m_playingSounds.push_back(sound);
@@ -412,3 +820,75 @@ void AUD_SoftwareDevice::setVolume(float volume)
 {
        m_volume = volume;
 }
+
+/******************************************************************************/
+/**************************** 3D Device Code **********************************/
+/******************************************************************************/
+
+AUD_Vector3 AUD_SoftwareDevice::getListenerLocation() const
+{
+       return m_location;
+}
+
+void AUD_SoftwareDevice::setListenerLocation(const AUD_Vector3& location)
+{
+       m_location = location;
+}
+
+AUD_Vector3 AUD_SoftwareDevice::getListenerVelocity() const
+{
+       return m_velocity;
+}
+
+void AUD_SoftwareDevice::setListenerVelocity(const AUD_Vector3& velocity)
+{
+       m_velocity = velocity;
+}
+
+AUD_Quaternion AUD_SoftwareDevice::getListenerOrientation() const
+{
+       return m_orientation;
+}
+
+void AUD_SoftwareDevice::setListenerOrientation(const AUD_Quaternion& orientation)
+{
+       m_orientation = orientation;
+}
+
+float AUD_SoftwareDevice::getSpeedOfSound() const
+{
+       return m_speed_of_sound;
+}
+
+void AUD_SoftwareDevice::setSpeedOfSound(float speed)
+{
+       m_speed_of_sound = speed;
+}
+
+float AUD_SoftwareDevice::getDopplerFactor() const
+{
+       return m_doppler_factor;
+}
+
+void AUD_SoftwareDevice::setDopplerFactor(float factor)
+{
+       m_doppler_factor = factor;
+       if(factor == 0)
+               m_flags |= AUD_RENDER_DOPPLER;
+       else
+               m_flags &= ~AUD_RENDER_DOPPLER;
+}
+
+AUD_DistanceModel AUD_SoftwareDevice::getDistanceModel() const
+{
+       return m_distance_model;
+}
+
+void AUD_SoftwareDevice::setDistanceModel(AUD_DistanceModel model)
+{
+       m_distance_model = model;
+       if(model == AUD_DISTANCE_MODEL_INVALID)
+               m_flags |= AUD_RENDER_DISTANCE;
+       else
+               m_flags &= ~AUD_RENDER_DISTANCE;
+}
index 58aaebddb96b5340616b87652918d2f2e1917a26..c7dbf1d41ebc4987a6c817db46abface9feae118 100644 (file)
 
 #include "AUD_IDevice.h"
 #include "AUD_IHandle.h"
+#include "AUD_I3DDevice.h"
+#include "AUD_I3DHandle.h"
 #include "AUD_Mixer.h"
 #include "AUD_Buffer.h"
 #include "AUD_PitchReader.h"
+#include "AUD_ChannelMapperReader.h"
 
 #include <list>
 #include <pthread.h>
  *  - Call the create and destroy functions.
  *  - Call the mix function to retrieve their audio data.
  */
-class AUD_SoftwareDevice : public AUD_IDevice
+class AUD_SoftwareDevice : public AUD_IDevice, public AUD_I3DDevice
 {
 protected:
        /// Saves the data for playback.
-       class AUD_SoftwareHandle : public AUD_IHandle
+       class AUD_SoftwareHandle : public AUD_IHandle, public AUD_I3DHandle
        {
        public:
                /// The reader source.
@@ -62,15 +65,63 @@ protected:
                /// The pitch reader in between.
                AUD_Reference<AUD_PitchReader> m_pitch;
 
+               /// The channel mapper reader in between.
+               AUD_Reference<AUD_ChannelMapperReader> m_mapper;
+
                /// Whether to keep the source if end of it is reached.
                bool m_keep;
 
-               /// The volume of the source.
+               /// The user set pitch of the source.
+               float m_user_pitch;
+
+               /// The user set volume of the source.
+               float m_user_volume;
+
+               /// The calculated final volume of the source.
                float m_volume;
 
                /// The loop count of the source.
                int m_loopcount;
 
+               /// Location in 3D Space.
+               AUD_Vector3 m_location;
+
+               /// Velocity in 3D Space.
+               AUD_Vector3 m_velocity;
+
+               /// Orientation in 3D Space.
+               AUD_Quaternion m_orientation;
+
+               /// Whether the position to the listener is relative or absolute
+               bool m_relative;
+
+               /// Maximum volume.
+               float m_volume_max;
+
+               /// Minimum volume.
+               float m_volume_min;
+
+               /// Maximum distance.
+               float m_distance_max;
+
+               /// Reference distance;
+               float m_distance_reference;
+
+               /// Attenuation
+               float m_attenuation;
+
+               /// Cone outer angle.
+               float m_cone_angle_outer;
+
+               /// Cone inner angle.
+               float m_cone_angle_inner;
+
+               /// Cone outer volume.
+               float m_cone_volume_outer;
+
+               /// Rendering flags
+               int m_flags;
+
                /// The stop callback.
                stopCallback m_stop;
 
@@ -85,7 +136,9 @@ protected:
 
        public:
 
-               AUD_SoftwareHandle(AUD_SoftwareDevice* device, AUD_Reference<AUD_IReader> reader, AUD_Reference<AUD_PitchReader> pitch, bool keep);
+               AUD_SoftwareHandle(AUD_SoftwareDevice* device, AUD_Reference<AUD_IReader> reader, AUD_Reference<AUD_PitchReader> pitch, AUD_Reference<AUD_ChannelMapperReader> mapper, bool keep);
+
+               void update();
 
                virtual ~AUD_SoftwareHandle() {}
                virtual bool pause();
@@ -103,6 +156,31 @@ protected:
                virtual int getLoopCount();
                virtual bool setLoopCount(int count);
                virtual bool setStopCallback(stopCallback callback = 0, void* data = 0);
+
+               virtual AUD_Vector3 getSourceLocation();
+               virtual bool setSourceLocation(const AUD_Vector3& location);
+               virtual AUD_Vector3 getSourceVelocity();
+               virtual bool setSourceVelocity(const AUD_Vector3& velocity);
+               virtual AUD_Quaternion getSourceOrientation();
+               virtual bool setSourceOrientation(const AUD_Quaternion& orientation);
+               virtual bool isRelative();
+               virtual bool setRelative(bool relative);
+               virtual float getVolumeMaximum();
+               virtual bool setVolumeMaximum(float volume);
+               virtual float getVolumeMinimum();
+               virtual bool setVolumeMinimum(float volume);
+               virtual float getDistanceMaximum();
+               virtual bool setDistanceMaximum(float distance);
+               virtual float getDistanceReference();
+               virtual bool setDistanceReference(float distance);
+               virtual float getAttenuation();
+               virtual bool setAttenuation(float factor);
+               virtual float getConeAngleOuter();
+               virtual bool setConeAngleOuter(float angle);
+               virtual float getConeAngleInner();
+               virtual bool setConeAngleInner(float angle);
+               virtual float getConeVolumeOuter();
+               virtual bool setConeVolumeOuter(float volume);
        };
 
        typedef std::list<AUD_Reference<AUD_SoftwareHandle> >::iterator AUD_HandleIterator;
@@ -171,6 +249,27 @@ private:
         */
        float m_volume;
 
+       /// Listener location.
+       AUD_Vector3 m_location;
+
+       /// Listener velocity.
+       AUD_Vector3 m_velocity;
+
+       /// Listener orientation.
+       AUD_Quaternion m_orientation;
+
+       /// Speed of Sound.
+       float m_speed_of_sound;
+
+       /// Doppler factor.
+       float m_doppler_factor;
+
+       /// Distance model.
+       AUD_DistanceModel m_distance_model;
+
+       /// Rendering flags
+       int m_flags;
+
 public:
        virtual AUD_DeviceSpecs getSpecs() const;
        virtual AUD_Reference<AUD_IHandle> play(AUD_Reference<AUD_IReader> reader, bool keep = false);
@@ -179,6 +278,19 @@ public:
        virtual void unlock();
        virtual float getVolume() const;
        virtual void setVolume(float volume);
+
+       virtual AUD_Vector3 getListenerLocation() const;
+       virtual void setListenerLocation(const AUD_Vector3& location);
+       virtual AUD_Vector3 getListenerVelocity() const;
+       virtual void setListenerVelocity(const AUD_Vector3& velocity);
+       virtual AUD_Quaternion getListenerOrientation() const;
+       virtual void setListenerOrientation(const AUD_Quaternion& orientation);
+       virtual float getSpeedOfSound() const;
+       virtual void setSpeedOfSound(float speed);
+       virtual float getDopplerFactor() const;
+       virtual void setDopplerFactor(float factor);
+       virtual AUD_DistanceModel getDistanceModel() const;
+       virtual void setDistanceModel(AUD_DistanceModel model);
 };
 
 #endif //AUD_SOFTWAREDEVICE