3D Audio GSoC:
authorJoerg Mueller <nexyon@gmail.com>
Sat, 23 Jul 2011 15:59:10 +0000 (15:59 +0000)
committerJoerg Mueller <nexyon@gmail.com>
Sat, 23 Jul 2011 15:59:10 +0000 (15:59 +0000)
* Reviewed and improved the linear resampler. Now it should work pretty good also for special cases that caused errors previously.
* Fixed a crash in the GE when a sound actuator doesn't have a sound assigned.
* Corrected the OpenAL device's threading code. This is a bugfix for #27913, thanks to Juha Mäki-Kanto for helping to resolve this.

intern/audaspace/OpenAL/AUD_OpenALDevice.cpp
intern/audaspace/OpenAL/AUD_OpenALDevice.h
intern/audaspace/intern/AUD_LinearResampleReader.cpp
source/gameengine/Ketsji/KX_SoundActuator.cpp

index 65b1d3f..684ad50 100644 (file)
@@ -775,12 +775,15 @@ void* AUD_openalRunThread(void* device)
        return NULL;
 }
 
-void AUD_OpenALDevice::start()
+void AUD_OpenALDevice::start(bool join)
 {
        lock();
 
        if(!m_playing)
        {
+               if(join)
+                       pthread_join(m_thread, NULL);
+
                pthread_attr_t attr;
                pthread_attr_init(&attr);
                pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
@@ -943,8 +946,8 @@ void AUD_OpenALDevice::updateStreams()
                // stop thread
                if(m_playingSounds.empty() || (cerr != ALC_NO_ERROR))
                {
-                       unlock();
                        m_playing = false;
+                       unlock();
                        pthread_exit(NULL);
                }
 
@@ -1023,6 +1026,8 @@ AUD_OpenALDevice::AUD_OpenALDevice(AUD_DeviceSpecs specs, int buffersize)
        pthread_mutex_init(&m_mutex, &attr);
 
        pthread_mutexattr_destroy(&attr);
+
+       start(false);
 }
 
 AUD_OpenALDevice::~AUD_OpenALDevice()
@@ -1048,13 +1053,8 @@ AUD_OpenALDevice::~AUD_OpenALDevice()
        alcProcessContext(m_context);
 
        // wait for the thread to stop
-       if(m_playing)
-       {
-               unlock();
-               pthread_join(m_thread, NULL);
-       }
-       else
-               unlock();
+       unlock();
+       pthread_join(m_thread, NULL);
 
        //delete m_bufferedFactories;
 
index ea4f9ca..3ba761b 100644 (file)
@@ -207,7 +207,7 @@ private:
        /**
         * Starts the streaming thread.
         */
-       void start();
+       void start(bool join = true);
 
        /**
         * Gets the format according to the specs.
index c33017e..db050b5 100644 (file)
@@ -63,7 +63,7 @@ int AUD_LinearResampleReader::getLength() const
 
 int AUD_LinearResampleReader::getPosition() const
 {
-       return floor((m_reader->getPosition() + (m_cache_ok ? m_cache_pos - 2 : 0))
+       return floor((m_reader->getPosition() + (m_cache_ok ? m_cache_pos - 1 : 0))
                                 * m_rate / m_reader->getSpecs().rate);
 }
 
@@ -76,6 +76,9 @@ AUD_Specs AUD_LinearResampleReader::getSpecs() const
 
 void AUD_LinearResampleReader::read(int& length, bool& eos, sample_t* buffer)
 {
+       if(length == 0)
+               return;
+
        AUD_Specs specs = m_reader->getSpecs();
 
        int samplesize = AUD_SAMPLE_SIZE(specs);
@@ -85,13 +88,6 @@ void AUD_LinearResampleReader::read(int& length, bool& eos, sample_t* buffer)
        sample_t low, high;
        eos = false;
 
-       if(factor == 1 && (!m_cache_ok || m_cache_pos == 0))
-       {
-               // can read directly!
-               m_reader->read(length, eos, buffer);
-               return;
-       }
-
        // check for channels changed
 
        if(specs.channels != m_channels)
@@ -101,47 +97,65 @@ void AUD_LinearResampleReader::read(int& length, bool& eos, sample_t* buffer)
                m_cache_ok = false;
        }
 
+       if(factor == 1 && (!m_cache_ok || m_cache_pos == 1))
+       {
+               // can read directly!
+               m_reader->read(length, eos, buffer);
+
+               if(length > 0)
+               {
+                       memcpy(m_cache.getBuffer() + m_channels, buffer + m_channels * (length - 1), samplesize);
+                       m_cache_pos = 1;
+                       m_cache_ok = true;
+               }
+
+               return;
+       }
+
        int len;
        sample_t* buf;
 
        if(m_cache_ok)
        {
-               int need = ceil(length / factor - (1 - m_cache_pos));
+               int need = ceil(length / factor + m_cache_pos) - 1;
 
                len = need;
 
-               m_buffer.assureSize((len + 3) * samplesize);
+               m_buffer.assureSize((len + 2) * samplesize);
                buf = m_buffer.getBuffer();
 
                memcpy(buf, m_cache.getBuffer(), 2 * samplesize);
                m_reader->read(len, eos, buf + 2 * m_channels);
 
                if(len < need)
-                       length = floor((len + (1 - m_cache_pos)) * factor);
+                       length = floor((len + 1 - m_cache_pos) * factor);
        }
        else
        {
-               int need = ceil(length / factor) + 1;
+               m_cache_pos = 1 - 1 / factor;
+
+               int need = ceil(length / factor + m_cache_pos);
 
                len = need;
 
                m_buffer.assureSize((len + 1) * samplesize);
                buf = m_buffer.getBuffer();
 
-               m_reader->read(len, eos, buf);
+               memset(buf, 0, samplesize);
+               m_reader->read(len, eos, buf + m_channels);
+
+               if(len == 0)
+               {
+                       length = 0;
+                       return;
+               }
 
                if(len < need)
                {
-                       if(eos)
-                       {
-                               length = floor(len * factor);
-                               memset(buf + len * m_channels, 0, samplesize);
-                       }
-                       else
-                               length = ceil((len - 1) * factor);
+                       length = floor((len - m_cache_pos) * factor);
                }
+
                m_cache_ok = true;
-               m_cache_pos = 0;
        }
 
        for(int channel = 0; channel < m_channels; channel++)
@@ -159,7 +173,7 @@ void AUD_LinearResampleReader::read(int& length, bool& eos, sample_t* buffer)
 
        if(floor(spos) == spos)
        {
-               memcpy(m_cache.getBuffer(), buf + int(floor(spos - 1)) * m_channels, 2 * samplesize);
+               memcpy(m_cache.getBuffer() + m_channels, buf + int(floor(spos)) * m_channels, samplesize);
                m_cache_pos = 1;
        }
        else
index 0e7b00a..0f2597c 100644 (file)
@@ -57,7 +57,10 @@ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj,
                                                                   KX_SOUNDACT_TYPE type)//,
                                                                   : SCA_IActuator(gameobj, KX_ACT_SOUND)
 {
-       m_sound = AUD_copy(sound);
+       if(sound)
+               m_sound = AUD_copy(sound);
+       else
+               m_sound = NULL;
        m_volume = volume;
        m_pitch = pitch;
        m_is3d = is3d;
@@ -73,7 +76,8 @@ KX_SoundActuator::~KX_SoundActuator()
 {
        if(m_handle)
                AUD_stop(m_handle);
-       AUD_unload(m_sound);
+       if(m_sound)
+               AUD_unload(m_sound);
 }
 
 void KX_SoundActuator::play()
@@ -421,7 +425,10 @@ PyObject* KX_SoundActuator::pyattr_get_pitch(void *self, const struct KX_PYATTRI
 PyObject* KX_SoundActuator::pyattr_get_sound(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
 {
        KX_SoundActuator * actuator = static_cast<KX_SoundActuator *> (self);
-       return AUD_getPythonFactory(actuator->m_sound);
+       if(actuator->m_sound)
+               return AUD_getPythonFactory(actuator->m_sound);
+       else
+               Py_RETURN_NONE;
 }
 
 int KX_SoundActuator::pyattr_set_3d_property(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
@@ -535,7 +542,8 @@ int KX_SoundActuator::pyattr_set_sound(void *self, const struct KX_PYATTRIBUTE_D
        AUD_Sound* snd = AUD_getPythonSound(sound);
        if(snd)
        {
-               AUD_unload(actuator->m_sound);
+               if(actuator->m_sound)
+                       AUD_unload(actuator->m_sound);
                actuator->m_sound = snd;
                return PY_SET_ATTR_SUCCESS;
        }