Fix for [#37362] Audio strips sometimes are evaluated incorrectly.
authorJoerg Mueller <nexyon@gmail.com>
Tue, 12 Nov 2013 18:29:08 +0000 (18:29 +0000)
committerJoerg Mueller <nexyon@gmail.com>
Tue, 12 Nov 2013 18:29:08 +0000 (18:29 +0000)
For details see bug comments. The problem was that blender's animation system didn't update the audio animation system anymore due to an optimization. Fixed this in a complex but proper way in the audio animation system, so that it can handle gaps of missing values.

intern/audaspace/intern/AUD_AnimateableProperty.cpp
intern/audaspace/intern/AUD_AnimateableProperty.h

index 0b333e687ff375502880a00ea8dbf753bcdbf750..6d1a307d868bd4a0f3d943f19e695f9cd300c68e 100644 (file)
@@ -47,6 +47,15 @@ AUD_AnimateableProperty::AUD_AnimateableProperty(int count) :
        pthread_mutexattr_destroy(&attr);
 }
 
+void AUD_AnimateableProperty::updateUnknownCache(int start, int end)
+{
+       float* buf = getBuffer();
+
+       for(int i = start; i <= end; i++)
+               // TODO: maybe first instead of zero order interpolation?
+               memcpy(buf + i * m_count, buf + (start - 1) * m_count, m_count * sizeof(float));
+}
+
 AUD_AnimateableProperty::~AUD_AnimateableProperty()
 {
        pthread_mutex_destroy(&m_mutex);
@@ -67,6 +76,7 @@ void AUD_AnimateableProperty::write(const float* data)
        AUD_MutexLock lock(*this);
 
        m_isAnimated = false;
+       m_unknown.clear();
        memcpy(getBuffer(), data, m_count * sizeof(float));
 }
 
@@ -74,18 +84,85 @@ void AUD_AnimateableProperty::write(const float* data, int position, int count)
 {
        AUD_MutexLock lock(*this);
 
-       m_isAnimated = true;
-
        int pos = getSize() / (sizeof(float) * m_count);
 
+       if(!m_isAnimated)
+               pos = 0;
+
+       m_isAnimated = true;
+
        assureSize((count + position) * m_count * sizeof(float), true);
 
        float* buf = getBuffer();
 
        memcpy(buf + position * m_count, data, count * m_count * sizeof(float));
 
-       for(int i = pos; i < position; i++)
-               memcpy(buf + i * m_count, buf + (pos - 1) * m_count, m_count * sizeof(float));
+       // have to fill up space between?
+       if(pos < position)
+       {
+               m_unknown.push_back(Unknown(pos, position - 1));
+
+               if(pos == 0)
+               {
+                       memset(buf, 0, position * m_count * sizeof(float));
+               }
+               else
+                       updateUnknownCache(pos, position - 1);
+       }
+       // otherwise it's not at the end, let's check if some unknown part got filled
+       else
+       {
+               for(std::list<Unknown>::iterator it = m_unknown.begin(); it != m_unknown.end(); it++)
+               {
+                       // unknown area before position
+                       if(it->end < position)
+                               continue;
+
+                       // we're after the new area, let's stop
+                       if(it->start >= position + count)
+                               break;
+
+                       // we have an intersection, now 4 cases:
+                       // the start is included
+                       if(position <= it->start)
+                       {
+                               // the end is included
+                               if(position + count > it->end)
+                               {
+                                       // simply delete
+                                       std::list<Unknown>::iterator it2 = it;
+                                       it++;
+                                       m_unknown.erase(it2);
+                               }
+                               // the end is excluded, a second part remains
+                               else
+                               {
+                                       // update second part
+                                       it->start = position + count;
+                                       updateUnknownCache(it->start, it->end);
+                                       break;
+                               }
+                       }
+                       // start is excluded, a first part remains
+                       else
+                       {
+                               // the end is included
+                               if(position + count > it->end)
+                               {
+                                       // update first part
+                                       it->end = position - 1;
+                               }
+                               // the end is excluded, a second part remains
+                               else
+                               {
+                                       // add another item and update both parts
+                                       m_unknown.insert(it, Unknown(it->start, position - 1));
+                                       it->start = position + count;
+                                       updateUnknownCache(it->start, it->end);
+                               }
+                       }
+               }
+       }
 }
 
 void AUD_AnimateableProperty::read(float position, float* out)
index 322748ad5717918350034d2f553a852d0b1d7436..37eb8f845505866f715d9a09cc66209bb113d3e0 100644 (file)
@@ -34,6 +34,7 @@
 #include "AUD_ILockable.h"
 
 #include <pthread.h>
+#include <list>
 
 /**
  * This class saves animation data for float properties.
 class AUD_AnimateableProperty : private AUD_Buffer, public AUD_ILockable
 {
 private:
+       struct Unknown {
+               int start;
+               int end;
+
+               Unknown(int start, int end) :
+                       start(start), end(end) {}
+       };
+
        /// The count of floats for a single property.
        const int m_count;
 
@@ -50,10 +59,15 @@ private:
        /// The mutex for locking.
        pthread_mutex_t m_mutex;
 
+       /// The list of unknown buffer areas.
+       std::list<Unknown> m_unknown;
+
        // hide copy constructor and operator=
        AUD_AnimateableProperty(const AUD_AnimateableProperty&);
        AUD_AnimateableProperty& operator=(const AUD_AnimateableProperty&);
 
+       void updateUnknownCache(int start, int end);
+
 public:
        /**
         * Creates a new animateable property.