PluginInfo::type added to copy constructor. But why is the copy constructor defined...
[ardour.git] / libs / ardour / automation_event.cc
index a2eeebed5603e4b75f86a59796b390836aec321a..d5a7d50bb11942629d53b31e84962e2098f8f265 100644 (file)
@@ -14,8 +14,7 @@
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-    $Id$
 */
 
 #include <set>
@@ -26,6 +25,7 @@
 #include <algorithm>
 #include <sigc++/bind.h>
 #include <ardour/automation_event.h>
+#include <pbd/stacktrace.h>
 
 #include "i18n.h"
 
@@ -36,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 = "")
 {
@@ -49,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;
@@ -62,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;
@@ -81,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
@@ -95,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;
@@ -108,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 */
 
@@ -128,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;
@@ -140,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);
 
@@ -176,7 +185,10 @@ AutomationList::operator= (const AutomationList& other)
                max_yval = other.max_yval;
                max_xval = other.max_xval;
                default_value = other.default_value;
-               
+
+               rt_insertion_point = events.end();
+               lookup_cache.range.first = events.end();
+       
                mark_dirty ();
                maybe_signal_changed ();
        }
@@ -192,7 +204,7 @@ AutomationList::maybe_signal_changed ()
        if (_frozen) {
                changed_when_thawed = true;
        } else {
-               StateChanged (Change (0));
+               StateChanged ();
        }
 }
 
@@ -355,6 +367,7 @@ AutomationList::rt_add (double when, double value)
                
                if (!done) {
                        last_rt_insertion_point = events.insert (where, point_factory (when, value));
+                       // cerr << "\tINSERTED\n";
                }
                
                _new_touch = false;
@@ -401,7 +414,7 @@ AutomationList::add (double when, double value)
                }
 
                if (insert) {
-
+                       
                        events.insert (insertion_point, point_factory (when, value));
                        reposition_for_rt_add (0);
 
@@ -511,15 +524,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)
 {
@@ -530,11 +571,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 ();
 }
 
@@ -575,15 +628,33 @@ 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(Change(0)); /* EMIT SIGNAL */
+               StateChanged(); /* EMIT SIGNAL */
        }
 }
 
@@ -606,7 +677,7 @@ AutomationList::truncate_end (double last_coordinate)
        {
                Glib::Mutex::Lock lm (lock);
                ControlEvent cp (last_coordinate, 0);
-               list<ControlEvent*>::reverse_iterator i;
+               AutomationList::reverse_iterator i;
                double last_val;
 
                if (events.empty()) {
@@ -675,7 +746,7 @@ AutomationList::truncate_end (double last_coordinate)
                        uint32_t sz = events.size();
                        
                        while (i != events.rend() && sz > 2) {
-                               list<ControlEvent*>::reverse_iterator tmp;
+                               AutomationList::reverse_iterator tmp;
                                
                                tmp = i;
                                ++tmp;
@@ -772,7 +843,7 @@ AutomationList::truncate_start (double overall_length)
                        i = events.begin();
                        
                        while (i != events.end() && !events.empty()) {
-                               list<ControlEvent*>::iterator tmp;
+                               AutomationList::iterator tmp;
                                
                                tmp = i;
                                ++tmp;
@@ -872,6 +943,9 @@ AutomationList::shared_eval (double x)
                return multipoint_eval (x);
                break;
        }
+
+       /*NOTREACHED*/ /* stupid gcc */
+       return 0.0;
 }
 
 double
@@ -1176,6 +1250,8 @@ AutomationList::serialize_events ()
 {
        XMLNode* node = new XMLNode (X_("events"));
        stringstream str;
+       
+       str.precision(15);  //10 digits is enough digits for 24 hours at 96kHz
 
        for (iterator xx = events.begin(); xx != events.end(); ++xx) {
                str << (double) (*xx)->when;
@@ -1239,6 +1315,7 @@ AutomationList::deserialize_events (const XMLNode& node)
        }
 
        thaw ();
+
        return 0;
 }
 
@@ -1246,6 +1323,7 @@ int
 AutomationList::set_state (const XMLNode& node)
 {
        XMLNodeList nlist = node.children();
+       XMLNode* nsos;
        XMLNodeIterator niter;
        const XMLProperty* prop;
 
@@ -1256,6 +1334,11 @@ AutomationList::set_state (const XMLNode& node)
        
        if (node.name() == X_("Envelope") || node.name() == X_("FadeOut") || node.name() == X_("FadeIn")) {
 
+               if ((nsos = node.child (X_("AutomationList")))) {
+                       /* new school in old school clothing */
+                       return set_state (*nsos);
+               }
+
                /* old school */
 
                const XMLNodeList& elist = node.children();
@@ -1264,6 +1347,7 @@ AutomationList::set_state (const XMLNode& node)
                jack_nframes_t x;
                double y;
                
+               freeze ();
                clear ();
                
                for (i = elist.begin(); i != elist.end(); ++i) {
@@ -1280,9 +1364,11 @@ AutomationList::set_state (const XMLNode& node)
                        }
                        y = atof (prop->value().c_str());
                        
-                       add (x, y);
+                       fast_simple_add (x, y);
                }
                
+               thaw ();
+
                return 0;
        }
 
@@ -1338,7 +1424,24 @@ AutomationList::set_state (const XMLNode& node)
                        deserialize_events (*(*niter));
                }
        }
-       
+
        return 0;
 }
 
+void
+AutomationList::shift (nframes64_t pos, nframes64_t frames)
+{
+       {
+               Glib::Mutex::Lock lm (lock);
+
+               for (iterator i = begin (); i != end (); ++i) {
+                       if ((*i)->when >= pos) {
+                               (*i)->when += frames;
+                       }
+               }
+
+               mark_dirty ();
+       }
+
+       maybe_signal_changed ();
+}