2 Copyright (C) 2002 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sigc++/bind.h>
27 #include <ardour/automation_event.h>
28 #include <pbd/stacktrace.h>
33 using namespace ARDOUR;
37 sigc::signal<void,AutomationList *> AutomationList::AutomationListCreated;
39 static bool sort_events_by_time (ControlEvent* a, ControlEvent* b)
41 return a->when < b->when;
45 static void dumpit (const AutomationList& al, string prefix = "")
47 cerr << prefix << &al << endl;
48 for (AutomationList::const_iterator i = al.const_begin(); i != al.const_end(); ++i) {
49 cerr << prefix << '\t' << (*i)->when << ',' << (*i)->value << endl;
55 AutomationList::AutomationList (double defval)
58 changed_when_thawed = false;
64 max_xval = 0; // means "no limit"
65 default_value = defval;
67 rt_insertion_point = events.end();
68 lookup_cache.left = -1;
69 lookup_cache.range.first = events.end();
72 AutomationListCreated(this);
75 AutomationList::AutomationList (const AutomationList& other)
78 changed_when_thawed = false;
79 _style = other._style;
80 min_yval = other.min_yval;
81 max_yval = other.max_yval;
82 max_xval = other.max_xval;
83 default_value = other.default_value;
84 _state = other._state;
85 _touching = other._touching;
87 rt_insertion_point = events.end();
88 lookup_cache.left = -1;
89 lookup_cache.range.first = events.end();
92 for (const_iterator i = other.events.begin(); i != other.events.end(); ++i) {
93 /* we have to use other point_factory() because
94 its virtual and we're in a constructor.
96 events.push_back (other.point_factory (**i));
100 AutomationListCreated(this);
103 AutomationList::AutomationList (const AutomationList& other, double start, double end)
106 changed_when_thawed = false;
107 _style = other._style;
108 min_yval = other.min_yval;
109 max_yval = other.max_yval;
110 max_xval = other.max_xval;
111 default_value = other.default_value;
112 _state = other._state;
113 _touching = other._touching;
115 rt_insertion_point = events.end();
116 lookup_cache.left = -1;
117 lookup_cache.range.first = events.end();
118 sort_pending = false;
120 /* now grab the relevant points, and shift them back if necessary */
122 AutomationList* section = const_cast<AutomationList*>(&other)->copy (start, end);
124 if (!section->empty()) {
125 for (AutomationList::iterator i = section->begin(); i != section->end(); ++i) {
126 events.push_back (other.point_factory ((*i)->when, (*i)->value));
134 AutomationListCreated(this);
137 AutomationList::AutomationList (const XMLNode& node)
140 changed_when_thawed = false;
144 max_xval = 0; // means "no limit"
148 rt_insertion_point = events.end();
149 lookup_cache.left = -1;
150 lookup_cache.range.first = events.end();
151 sort_pending = false;
155 AutomationListCreated(this);
158 AutomationList::~AutomationList()
162 for (AutomationEventList::iterator x = events.begin(); x != events.end(); ++x) {
168 AutomationList::operator== (const AutomationList& other)
170 return events == other.events;
174 AutomationList::operator= (const AutomationList& other)
176 if (this != &other) {
180 for (const_iterator i = other.events.begin(); i != other.events.end(); ++i) {
181 events.push_back (point_factory (**i));
184 min_yval = other.min_yval;
185 max_yval = other.max_yval;
186 max_xval = other.max_xval;
187 default_value = other.default_value;
189 rt_insertion_point = events.end();
190 lookup_cache.range.first = events.end();
193 maybe_signal_changed ();
200 AutomationList::maybe_signal_changed ()
205 changed_when_thawed = true;
212 AutomationList::set_automation_state (AutoState s)
216 automation_state_changed (); /* EMIT SIGNAL */
221 AutomationList::set_automation_style (AutoStyle s)
225 automation_style_changed (); /* EMIT SIGNAL */
230 AutomationList::start_touch ()
237 AutomationList::stop_touch ()
244 AutomationList::clear ()
247 Glib::Mutex::Lock lm (lock);
252 maybe_signal_changed ();
256 AutomationList::x_scale (double factor)
258 Glib::Mutex::Lock lm (lock);
263 AutomationList::extend_to (double when)
265 Glib::Mutex::Lock lm (lock);
266 if (events.empty() || events.back()->when == when) {
269 double factor = when / events.back()->when;
274 void AutomationList::_x_scale (double factor)
276 for (AutomationList::iterator i = events.begin(); i != events.end(); ++i) {
277 (*i)->when = floor ((*i)->when * factor);
284 AutomationList::reposition_for_rt_add (double when)
286 rt_insertion_point = events.end();
289 #define last_rt_insertion_point rt_insertion_point
292 AutomationList::rt_add (double when, double value)
294 /* this is for automation recording */
296 if ((_state & Touch) && !_touching) {
300 // cerr << "RT: alist @ " << this << " add " << value << " @ " << when << endl;
303 Glib::Mutex::Lock lm (lock);
307 ControlEvent cp (when, 0.0);
310 if ((last_rt_insertion_point != events.end()) && ((*last_rt_insertion_point)->when < when) ) {
312 /* we have a previous insertion point, so we should delete
313 everything between it and the position where we are going
314 to insert this point.
317 iterator after = last_rt_insertion_point;
319 if (++after != events.end()) {
320 iterator far = after;
322 while (far != events.end()) {
323 if ((*far)->when > when) {
331 last_rt_insertion_point = where;
333 if((*where)->when == when) {
334 (*where)->value = value;
338 where = events.erase (after, far);
347 iterator previous = last_rt_insertion_point;
350 if (last_rt_insertion_point != events.begin() && (*last_rt_insertion_point)->value == value && (*previous)->value == value) {
351 (*last_rt_insertion_point)->when = when;
358 where = lower_bound (events.begin(), events.end(), &cp, cmp);
360 if (where != events.end()) {
361 if ((*where)->when == when) {
362 (*where)->value = value;
369 last_rt_insertion_point = events.insert (where, point_factory (when, value));
370 // cerr << "\tINSERTED\n";
377 maybe_signal_changed ();
381 AutomationList::fast_simple_add (double when, double value)
383 /* to be used only for loading pre-sorted data from saved state */
384 events.insert (events.end(), point_factory (when, value));
387 #undef last_rt_insertion_point
390 AutomationList::add (double when, double value)
392 /* this is for graphical editing */
395 Glib::Mutex::Lock lm (lock);
397 ControlEvent cp (when, 0.0f);
399 iterator insertion_point;
401 for (insertion_point = lower_bound (events.begin(), events.end(), &cp, cmp); insertion_point != events.end(); ++insertion_point) {
403 /* only one point allowed per time point */
405 if ((*insertion_point)->when == when) {
406 (*insertion_point)->value = value;
411 if ((*insertion_point)->when >= when) {
418 events.insert (insertion_point, point_factory (when, value));
419 reposition_for_rt_add (0);
426 maybe_signal_changed ();
430 AutomationList::erase (AutomationList::iterator i)
433 Glib::Mutex::Lock lm (lock);
435 reposition_for_rt_add (0);
438 maybe_signal_changed ();
442 AutomationList::erase (AutomationList::iterator start, AutomationList::iterator end)
445 Glib::Mutex::Lock lm (lock);
446 events.erase (start, end);
447 reposition_for_rt_add (0);
450 maybe_signal_changed ();
454 AutomationList::reset_range (double start, double endt)
459 Glib::Mutex::Lock lm (lock);
461 ControlEvent cp (start, 0.0f);
465 if ((s = lower_bound (events.begin(), events.end(), &cp, cmp)) != events.end()) {
468 e = upper_bound (events.begin(), events.end(), &cp, cmp);
470 for (iterator i = s; i != e; ++i) {
471 (*i)->value = default_value;
481 maybe_signal_changed ();
486 AutomationList::erase_range (double start, double endt)
491 Glib::Mutex::Lock lm (lock);
493 ControlEvent cp (start, 0.0f);
497 if ((s = lower_bound (events.begin(), events.end(), &cp, cmp)) != events.end()) {
499 e = upper_bound (events.begin(), events.end(), &cp, cmp);
501 reposition_for_rt_add (0);
509 maybe_signal_changed ();
514 AutomationList::move_range (iterator start, iterator end, double xdelta, double ydelta)
516 /* note: we assume higher level logic is in place to avoid this
517 reordering the time-order of control events in the list. ie. all
518 points after end are later than (end)->when.
522 Glib::Mutex::Lock lm (lock);
524 while (start != end) {
525 (*start)->when += xdelta;
526 (*start)->value += ydelta;
527 if (isnan ((*start)->value)) {
534 events.sort (sort_events_by_time);
542 maybe_signal_changed ();
546 AutomationList::slide (iterator before, double distance)
549 Glib::Mutex::Lock lm (lock);
551 if (before == events.end()) {
555 while (before != events.end()) {
556 (*before)->when += distance;
561 maybe_signal_changed ();
565 AutomationList::modify (iterator iter, double when, double val)
567 /* note: we assume higher level logic is in place to avoid this
568 reordering the time-order of control events in the list. ie. all
569 points after *iter are later than when.
573 Glib::Mutex::Lock lm (lock);
575 (*iter)->when = when;
576 (*iter)->value = val;
583 events.sort (sort_events_by_time);
591 maybe_signal_changed ();
594 std::pair<AutomationList::iterator,AutomationList::iterator>
595 AutomationList::control_points_adjacent (double xval)
597 Glib::Mutex::Lock lm (lock);
600 ControlEvent cp (xval, 0.0f);
601 std::pair<iterator,iterator> ret;
603 ret.first = events.end();
604 ret.second = events.end();
606 for (i = lower_bound (events.begin(), events.end(), &cp, cmp); i != events.end(); ++i) {
608 if (ret.first == events.end()) {
609 if ((*i)->when >= xval) {
610 if (i != events.begin()) {
619 if ((*i)->when > xval) {
629 AutomationList::freeze ()
635 AutomationList::thaw ()
638 PBD::stacktrace (cerr);
639 fatal << string_compose (_("programming error: %1"), X_("AutomationList::thaw() called while not frozen")) << endmsg;
648 Glib::Mutex::Lock lm (lock);
651 events.sort (sort_events_by_time);
652 sort_pending = false;
656 if (changed_when_thawed) {
657 StateChanged(); /* EMIT SIGNAL */
662 AutomationList::set_max_xval (double x)
668 AutomationList::mark_dirty ()
670 lookup_cache.left = -1;
675 AutomationList::truncate_end (double last_coordinate)
678 Glib::Mutex::Lock lm (lock);
679 ControlEvent cp (last_coordinate, 0);
680 AutomationList::reverse_iterator i;
683 if (events.empty()) {
687 if (last_coordinate == events.back()->when) {
691 if (last_coordinate > events.back()->when) {
696 iterator foo = events.begin();
699 if (foo == events.end()) {
701 } else if (++foo == events.end()) {
708 /* less than 2 points: add a new point */
709 events.push_back (point_factory (last_coordinate, events.back()->value));
712 /* more than 2 points: check to see if the last 2 values
713 are equal. if so, just move the position of the
714 last point. otherwise, add a new point.
717 iterator penultimate = events.end();
718 --penultimate; /* points at last point */
719 --penultimate; /* points at the penultimate point */
721 if (events.back()->value == (*penultimate)->value) {
722 events.back()->when = last_coordinate;
724 events.push_back (point_factory (last_coordinate, events.back()->value));
732 last_val = unlocked_eval (last_coordinate);
733 last_val = max ((double) min_yval, last_val);
734 last_val = min ((double) max_yval, last_val);
738 /* make i point to the last control point */
742 /* now go backwards, removing control points that are
743 beyond the new last coordinate.
746 uint32_t sz = events.size();
748 while (i != events.rend() && sz > 2) {
749 AutomationList::reverse_iterator tmp;
754 if ((*i)->when < last_coordinate) {
758 events.erase (i.base());
764 events.back()->when = last_coordinate;
765 events.back()->value = last_val;
768 reposition_for_rt_add (0);
772 maybe_signal_changed ();
776 AutomationList::truncate_start (double overall_length)
779 Glib::Mutex::Lock lm (lock);
780 AutomationList::iterator i;
781 double first_legal_value;
782 double first_legal_coordinate;
784 if (events.empty()) {
785 fatal << _("programming error:")
786 << "AutomationList::truncate_start() called on an empty list"
792 if (overall_length == events.back()->when) {
793 /* no change in overall length */
797 if (overall_length > events.back()->when) {
799 /* growing at front: duplicate first point. shift all others */
801 double shift = overall_length - events.back()->when;
804 for (np = 0, i = events.begin(); i != events.end(); ++i, ++np) {
810 /* less than 2 points: add a new point */
811 events.push_front (point_factory (0, events.front()->value));
815 /* more than 2 points: check to see if the first 2 values
816 are equal. if so, just move the position of the
817 first point. otherwise, add a new point.
820 iterator second = events.begin();
821 ++second; /* points at the second point */
823 if (events.front()->value == (*second)->value) {
824 /* first segment is flat, just move start point back to zero */
825 events.front()->when = 0;
827 /* leave non-flat segment in place, add a new leading point. */
828 events.push_front (point_factory (0, events.front()->value));
834 /* shrinking at front */
836 first_legal_coordinate = events.back()->when - overall_length;
837 first_legal_value = unlocked_eval (first_legal_coordinate);
838 first_legal_value = max (min_yval, first_legal_value);
839 first_legal_value = min (max_yval, first_legal_value);
841 /* remove all events earlier than the new "front" */
845 while (i != events.end() && !events.empty()) {
846 AutomationList::iterator tmp;
851 if ((*i)->when > first_legal_coordinate) {
861 /* shift all remaining points left to keep their same
865 for (i = events.begin(); i != events.end(); ++i) {
866 (*i)->when -= first_legal_coordinate;
869 /* add a new point for the interpolated new value */
871 events.push_front (point_factory (0, first_legal_value));
874 reposition_for_rt_add (0);
879 maybe_signal_changed ();
883 AutomationList::unlocked_eval (double x)
885 return shared_eval (x);
889 AutomationList::shared_eval (double x)
891 pair<AutomationEventList::iterator,AutomationEventList::iterator> range;
897 npoints = events.size();
901 return default_value;
904 if (x >= events.front()->when) {
905 return events.front()->value;
907 // return default_value;
908 return events.front()->value;
912 if (x >= events.back()->when) {
913 return events.back()->value;
914 } else if (x == events.front()->when) {
915 return events.front()->value;
916 } else if (x < events.front()->when) {
917 // return default_value;
918 return events.front()->value;
921 lpos = events.front()->when;
922 lval = events.front()->value;
923 upos = events.back()->when;
924 uval = events.back()->value;
926 /* linear interpolation betweeen the two points
929 fraction = (double) (x - lpos) / (double) (upos - lpos);
930 return lval + (fraction * (uval - lval));
934 if (x >= events.back()->when) {
935 return events.back()->value;
936 } else if (x == events.front()->when) {
937 return events.front()->value;
938 } else if (x < events.front()->when) {
939 // return default_value;
940 return events.front()->value;
943 return multipoint_eval (x);
947 /*NOTREACHED*/ /* stupid gcc */
952 AutomationList::multipoint_eval (double x)
954 pair<AutomationList::iterator,AutomationList::iterator> range;
959 /* only do the range lookup if x is in a different range than last time
960 this was called (or if the lookup cache has been marked "dirty" (left<0)
963 if ((lookup_cache.left < 0) ||
964 ((lookup_cache.left > x) ||
965 (lookup_cache.range.first == events.end()) ||
966 ((*lookup_cache.range.second)->when < x))) {
968 ControlEvent cp (x, 0);
971 lookup_cache.range = equal_range (events.begin(), events.end(), &cp, cmp);
974 range = lookup_cache.range;
976 if (range.first == range.second) {
978 /* x does not exist within the list as a control point */
980 lookup_cache.left = x;
982 if (range.first != events.begin()) {
984 lpos = (*range.first)->when;
985 lval = (*range.first)->value;
987 /* we're before the first point */
988 // return default_value;
989 return events.front()->value;
992 if (range.second == events.end()) {
993 /* we're after the last point */
994 return events.back()->value;
997 upos = (*range.second)->when;
998 uval = (*range.second)->value;
1000 /* linear interpolation betweeen the two points
1004 fraction = (double) (x - lpos) / (double) (upos - lpos);
1005 return lval + (fraction * (uval - lval));
1009 /* x is a control point in the data */
1010 lookup_cache.left = -1;
1011 return (*range.first)->value;
1015 AutomationList::cut (iterator start, iterator end)
1017 AutomationList* nal = new AutomationList (default_value);
1020 Glib::Mutex::Lock lm (lock);
1022 for (iterator x = start; x != end; ) {
1028 nal->events.push_back (point_factory (**x));
1031 reposition_for_rt_add (0);
1039 maybe_signal_changed ();
1045 AutomationList::cut_copy_clear (double start, double end, int op)
1047 AutomationList* nal = new AutomationList (default_value);
1049 ControlEvent cp (start, 0.0);
1051 bool changed = false;
1054 Glib::Mutex::Lock lm (lock);
1056 if ((s = lower_bound (events.begin(), events.end(), &cp, cmp)) == events.end()) {
1061 e = upper_bound (events.begin(), events.end(), &cp, cmp);
1063 if (op != 2 && (*s)->when != start) {
1064 nal->events.push_back (point_factory (0, unlocked_eval (start)));
1067 for (iterator x = s; x != e; ) {
1075 /* adjust new points to be relative to start, which
1076 has been set to zero.
1080 nal->events.push_back (point_factory ((*x)->when - start, (*x)->value));
1090 if (op != 2 && nal->events.back()->when != end - start) {
1091 nal->events.push_back (point_factory (end - start, unlocked_eval (end)));
1095 reposition_for_rt_add (0);
1101 maybe_signal_changed ();
1108 AutomationList::copy (iterator start, iterator end)
1110 AutomationList* nal = new AutomationList (default_value);
1113 Glib::Mutex::Lock lm (lock);
1115 for (iterator x = start; x != end; ) {
1121 nal->events.push_back (point_factory (**x));
1131 AutomationList::cut (double start, double end)
1133 return cut_copy_clear (start, end, 0);
1137 AutomationList::copy (double start, double end)
1139 return cut_copy_clear (start, end, 1);
1143 AutomationList::clear (double start, double end)
1145 (void) cut_copy_clear (start, end, 2);
1149 AutomationList::paste (AutomationList& alist, double pos, float times)
1151 if (alist.events.empty()) {
1156 Glib::Mutex::Lock lm (lock);
1160 ControlEvent cp (pos, 0.0);
1163 where = upper_bound (events.begin(), events.end(), &cp, cmp);
1165 for (iterator i = alist.begin();i != alist.end(); ++i) {
1166 events.insert (where, point_factory( (*i)->when+pos,( *i)->value));
1167 end = (*i)->when + pos;
1171 /* move all points after the insertion along the timeline by
1175 while (where != events.end()) {
1177 if ((*where)->when <= end) {
1180 events.erase(where);
1188 reposition_for_rt_add (0);
1192 maybe_signal_changed ();
1197 AutomationList::point_factory (double when, double val) const
1199 return new ControlEvent (when, val);
1203 AutomationList::point_factory (const ControlEvent& other) const
1205 return new ControlEvent (other);
1209 AutomationList::get_state ()
1211 return state (true);
1215 AutomationList::state (bool full)
1217 XMLNode* root = new XMLNode (X_("AutomationList"));
1219 LocaleGuard lg (X_("POSIX"));
1221 root->add_property ("id", _id.to_s());
1223 snprintf (buf, sizeof (buf), "%.12g", default_value);
1224 root->add_property ("default", buf);
1225 snprintf (buf, sizeof (buf), "%.12g", min_yval);
1226 root->add_property ("min_yval", buf);
1227 snprintf (buf, sizeof (buf), "%.12g", max_yval);
1228 root->add_property ("max_yval", buf);
1229 snprintf (buf, sizeof (buf), "%.12g", max_xval);
1230 root->add_property ("max_xval", buf);
1233 root->add_property ("state", auto_state_to_string (_state));
1235 /* never save anything but Off for automation state to a template */
1236 root->add_property ("state", auto_state_to_string (Off));
1239 root->add_property ("style", auto_style_to_string (_style));
1241 if (!events.empty()) {
1242 root->add_child_nocopy (serialize_events());
1249 AutomationList::serialize_events ()
1251 XMLNode* node = new XMLNode (X_("events"));
1254 str.precision(15); //10 digits is enough digits for 24 hours at 96kHz
1256 for (iterator xx = events.begin(); xx != events.end(); ++xx) {
1257 str << (double) (*xx)->when;
1259 str <<(double) (*xx)->value;
1263 /* XML is a bit wierd */
1265 XMLNode* content_node = new XMLNode (X_("foo")); /* it gets renamed by libxml when we set content */
1266 content_node->set_content (str.str());
1268 node->add_child_nocopy (*content_node);
1274 AutomationList::deserialize_events (const XMLNode& node)
1276 if (node.children().empty()) {
1280 XMLNode* content_node = node.children().front();
1282 if (content_node->content().empty()) {
1289 stringstream str (content_node->content());
1305 fast_simple_add (x, y);
1310 error << _("automation list: cannot load coordinates from XML, all points ignored") << endmsg;
1313 reposition_for_rt_add (0);
1314 maybe_signal_changed ();
1323 AutomationList::set_state (const XMLNode& node)
1325 XMLNodeList nlist = node.children();
1327 XMLNodeIterator niter;
1328 const XMLProperty* prop;
1330 if (node.name() == X_("events")) {
1331 /* partial state setting*/
1332 return deserialize_events (node);
1335 if (node.name() == X_("Envelope") || node.name() == X_("FadeOut") || node.name() == X_("FadeIn")) {
1337 if ((nsos = node.child (X_("AutomationList")))) {
1338 /* new school in old school clothing */
1339 return set_state (*nsos);
1344 const XMLNodeList& elist = node.children();
1345 XMLNodeConstIterator i;
1353 for (i = elist.begin(); i != elist.end(); ++i) {
1355 if ((prop = (*i)->property ("x")) == 0) {
1356 error << _("automation list: no x-coordinate stored for control point (point ignored)") << endmsg;
1359 x = atoi (prop->value().c_str());
1361 if ((prop = (*i)->property ("y")) == 0) {
1362 error << _("automation list: no y-coordinate stored for control point (point ignored)") << endmsg;
1365 y = atof (prop->value().c_str());
1367 fast_simple_add (x, y);
1375 if (node.name() != X_("AutomationList") ) {
1376 error << string_compose (_("AutomationList: passed XML node called %1, not \"AutomationList\" - ignored"), node.name()) << endmsg;
1380 if ((prop = node.property ("id")) != 0) {
1381 _id = prop->value ();
1382 /* update session AL list */
1383 AutomationListCreated(this);
1386 if ((prop = node.property (X_("default"))) != 0){
1387 default_value = atof (prop->value());
1389 default_value = 0.0;
1392 if ((prop = node.property (X_("style"))) != 0) {
1393 _style = string_to_auto_style (prop->value());
1398 if ((prop = node.property (X_("state"))) != 0) {
1399 _state = string_to_auto_state (prop->value());
1404 if ((prop = node.property (X_("min_yval"))) != 0) {
1405 min_yval = atof (prop->value ());
1410 if ((prop = node.property (X_("max_yval"))) != 0) {
1411 max_yval = atof (prop->value ());
1416 if ((prop = node.property (X_("max_xval"))) != 0) {
1417 max_xval = atof (prop->value ());
1419 max_xval = 0; // means "no limit ;
1422 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1423 if ((*niter)->name() == X_("events")) {
1424 deserialize_events (*(*niter));
1432 AutomationList::shift (nframes64_t pos, nframes64_t frames)
1435 Glib::Mutex::Lock lm (lock);
1437 for (iterator i = begin (); i != end (); ++i) {
1438 if ((*i)->when >= pos) {
1439 (*i)->when += frames;
1446 maybe_signal_changed ();