Merged with trunk R1705.
[ardour.git] / libs / ardour / automation_event.cc
index 5cc2f50e386d60cf4bde0aebfaef860b76d1d426..341fa82091902c0f4898320bf42d82cdeedf24b7 100644 (file)
@@ -15,7 +15,6 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
-    $Id$
 */
 
 #include <set>
@@ -26,7 +25,7 @@
 #include <algorithm>
 #include <sigc++/bind.h>
 #include <ardour/automation_event.h>
-#include <pbd/convert.h>
+#include <pbd/stacktrace.h>
 
 #include "i18n.h"
 
@@ -37,6 +36,11 @@ using namespace PBD;
 
 sigc::signal<void,AutomationList *> AutomationList::AutomationListCreated;
 
+static bool sort_events_by_time (ControlEvent* a, ControlEvent* b)
+{
+       return a->when < b->when;
+}
+
 #if 0
 static void dumpit (const AutomationList& al, string prefix = "")
 {
@@ -50,7 +54,7 @@ static void dumpit (const AutomationList& al, string prefix = "")
 
 AutomationList::AutomationList (double defval)
 {
-       _frozen = false;
+       _frozen = 0;
        changed_when_thawed = false;
        _state = Off;
        _style = Absolute;
@@ -63,13 +67,14 @@ AutomationList::AutomationList (double defval)
        rt_insertion_point = events.end();
        lookup_cache.left = -1;
        lookup_cache.range.first = events.end();
+       sort_pending = false;
 
         AutomationListCreated(this);
 }
 
 AutomationList::AutomationList (const AutomationList& other)
 {
-       _frozen = false;
+       _frozen = 0;
        changed_when_thawed = false;
        _style = other._style;
        min_yval = other.min_yval;
@@ -82,6 +87,7 @@ AutomationList::AutomationList (const AutomationList& other)
        rt_insertion_point = events.end();
        lookup_cache.left = -1;
        lookup_cache.range.first = events.end();
+       sort_pending = false;
 
        for (const_iterator i = other.events.begin(); i != other.events.end(); ++i) {
                /* we have to use other point_factory() because
@@ -96,7 +102,7 @@ AutomationList::AutomationList (const AutomationList& other)
 
 AutomationList::AutomationList (const AutomationList& other, double start, double end)
 {
-       _frozen = false;
+       _frozen = 0;
        changed_when_thawed = false;
        _style = other._style;
        min_yval = other.min_yval;
@@ -109,6 +115,7 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
        rt_insertion_point = events.end();
        lookup_cache.left = -1;
        lookup_cache.range.first = events.end();
+       sort_pending = false;
 
        /* now grab the relevant points, and shift them back if necessary */
 
@@ -129,7 +136,7 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
 
 AutomationList::AutomationList (const XMLNode& node)
 {
-       _frozen = false;
+       _frozen = 0;
        changed_when_thawed = false;
        _touching = false;
        min_yval = FLT_MIN;
@@ -141,6 +148,7 @@ AutomationList::AutomationList (const XMLNode& node)
        rt_insertion_point = events.end();
        lookup_cache.left = -1;
        lookup_cache.range.first = events.end();
+       sort_pending = false;
        
        set_state (node);
 
@@ -402,7 +410,7 @@ AutomationList::add (double when, double value)
                }
 
                if (insert) {
-
+                       
                        events.insert (insertion_point, point_factory (when, value));
                        reposition_for_rt_add (0);
 
@@ -512,15 +520,43 @@ AutomationList::move_range (iterator start, iterator end, double xdelta, double
                while (start != end) {
                        (*start)->when += xdelta;
                        (*start)->value += ydelta;
+                       if (isnan ((*start)->value)) {
+                               abort ();
+                       }
                        ++start;
                }
 
+               if (!_frozen) {
+                       events.sort (sort_events_by_time);
+               } else {
+                       sort_pending = true;
+               }
+
                mark_dirty ();
        }
 
        maybe_signal_changed ();
 }
 
+void
+AutomationList::slide (iterator before, double distance)
+{
+       {
+               Glib::Mutex::Lock lm (lock);
+
+               if (before == events.end()) {
+                       return;
+               }
+               
+               while (before != events.end()) {
+                       (*before)->when += distance;
+                       ++before;
+               }
+       }
+
+       maybe_signal_changed ();
+}
+
 void
 AutomationList::modify (iterator iter, double when, double val)
 {
@@ -531,11 +567,23 @@ AutomationList::modify (iterator iter, double when, double val)
 
        {
                Glib::Mutex::Lock lm (lock);
+
                (*iter)->when = when;
                (*iter)->value = val;
+
+               if (isnan (val)) {
+                       abort ();
+               }
+
+               if (!_frozen) {
+                       events.sort (sort_events_by_time);
+               } else {
+                       sort_pending = true;
+               }
+
                mark_dirty ();
        }
-       
+
        maybe_signal_changed ();
 }
 
@@ -576,13 +624,31 @@ AutomationList::control_points_adjacent (double xval)
 void
 AutomationList::freeze ()
 {
-       _frozen = true;
+       _frozen++;
 }
 
 void
 AutomationList::thaw ()
 {
-       _frozen = false;
+       if (_frozen == 0) {
+               PBD::stacktrace (cerr);
+               fatal << string_compose (_("programming error: %1"), X_("AutomationList::thaw() called while not frozen")) << endmsg;
+               /*NOTREACHED*/
+       }
+
+       if (--_frozen > 0) {
+               return;
+       }
+
+       {
+               Glib::Mutex::Lock lm (lock);
+
+               if (sort_pending) {
+                       events.sort (sort_events_by_time);
+                       sort_pending = false;
+               }
+       }
+
        if (changed_when_thawed) {
                StateChanged(); /* EMIT SIGNAL */
        }
@@ -1240,6 +1306,7 @@ AutomationList::deserialize_events (const XMLNode& node)
        }
 
        thaw ();
+
        return 0;
 }
 
@@ -1271,6 +1338,7 @@ AutomationList::set_state (const XMLNode& node)
                jack_nframes_t x;
                double y;
                
+               freeze ();
                clear ();
                
                for (i = elist.begin(); i != elist.end(); ++i) {
@@ -1287,9 +1355,11 @@ AutomationList::set_state (const XMLNode& node)
                        }
                        y = atof (prop->value().c_str());
                        
-                       add (x, y);
+                       fast_simple_add (x, y);
                }
                
+               thaw ();
+
                return 0;
        }
 
@@ -1345,7 +1415,7 @@ AutomationList::set_state (const XMLNode& node)
                        deserialize_events (*(*niter));
                }
        }
-       
+
        return 0;
 }