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.
27 #include <sigc++/bind.h>
28 #include <ardour/automation_event.h>
33 using namespace ARDOUR;
37 sigc::signal<void,AutomationList *> AutomationList::AutomationListCreated;
40 static void dumpit (const AutomationList& al, string prefix = "")
42 cerr << prefix << &al << endl;
43 for (AutomationList::const_iterator i = al.const_begin(); i != al.const_end(); ++i) {
44 cerr << prefix << '\t' << (*i)->when << ',' << (*i)->value << endl;
50 AutomationList::AutomationList (double defval)
53 changed_when_thawed = false;
59 max_xval = 0; // means "no limit"
60 default_value = defval;
62 rt_insertion_point = events.end();
63 lookup_cache.left = -1;
64 lookup_cache.range.first = events.end();
66 AutomationListCreated(this);
69 AutomationList::AutomationList (const AutomationList& other)
72 changed_when_thawed = false;
73 _style = other._style;
74 min_yval = other.min_yval;
75 max_yval = other.max_yval;
76 max_xval = other.max_xval;
77 default_value = other.default_value;
78 _state = other._state;
79 _touching = other._touching;
81 rt_insertion_point = events.end();
82 lookup_cache.left = -1;
83 lookup_cache.range.first = events.end();
85 for (const_iterator i = other.events.begin(); i != other.events.end(); ++i) {
86 /* we have to use other point_factory() because
87 its virtual and we're in a constructor.
89 events.push_back (other.point_factory (**i));
93 AutomationListCreated(this);
96 AutomationList::AutomationList (const AutomationList& other, double start, double end)
99 changed_when_thawed = false;
100 _style = other._style;
101 min_yval = other.min_yval;
102 max_yval = other.max_yval;
103 max_xval = other.max_xval;
104 default_value = other.default_value;
105 _state = other._state;
106 _touching = other._touching;
108 rt_insertion_point = events.end();
109 lookup_cache.left = -1;
110 lookup_cache.range.first = events.end();
112 /* now grab the relevant points, and shift them back if necessary */
114 AutomationList* section = const_cast<AutomationList*>(&other)->copy (start, end);
116 if (!section->empty()) {
117 for (AutomationList::iterator i = section->begin(); i != section->end(); ++i) {
118 events.push_back (other.point_factory ((*i)->when, (*i)->value));
126 AutomationListCreated(this);
129 AutomationList::AutomationList (const XMLNode& node)
132 changed_when_thawed = false;
136 max_xval = 0; // means "no limit"
140 rt_insertion_point = events.end();
141 lookup_cache.left = -1;
142 lookup_cache.range.first = events.end();
146 AutomationListCreated(this);
149 AutomationList::~AutomationList()
153 for (AutomationEventList::iterator x = events.begin(); x != events.end(); ++x) {
159 AutomationList::operator== (const AutomationList& other)
161 return events == other.events;
165 AutomationList::operator= (const AutomationList& other)
167 if (this != &other) {
171 for (const_iterator i = other.events.begin(); i != other.events.end(); ++i) {
172 events.push_back (point_factory (**i));
175 min_yval = other.min_yval;
176 max_yval = other.max_yval;
177 max_xval = other.max_xval;
178 default_value = other.default_value;
181 maybe_signal_changed ();
188 AutomationList::maybe_signal_changed ()
193 changed_when_thawed = true;
200 AutomationList::set_automation_state (AutoState s)
204 automation_state_changed (); /* EMIT SIGNAL */
209 AutomationList::set_automation_style (AutoStyle s)
213 automation_style_changed (); /* EMIT SIGNAL */
218 AutomationList::start_touch ()
225 AutomationList::stop_touch ()
232 AutomationList::clear ()
235 Glib::Mutex::Lock lm (lock);
240 maybe_signal_changed ();
244 AutomationList::x_scale (double factor)
246 Glib::Mutex::Lock lm (lock);
251 AutomationList::extend_to (double when)
253 Glib::Mutex::Lock lm (lock);
254 if (events.empty() || events.back()->when == when) {
257 double factor = when / events.back()->when;
262 void AutomationList::_x_scale (double factor)
264 for (AutomationList::iterator i = events.begin(); i != events.end(); ++i) {
265 (*i)->when = floor ((*i)->when * factor);
272 AutomationList::reposition_for_rt_add (double when)
274 rt_insertion_point = events.end();
277 #define last_rt_insertion_point rt_insertion_point
280 AutomationList::rt_add (double when, double value)
282 /* this is for automation recording */
284 if ((_state & Touch) && !_touching) {
288 // cerr << "RT: alist @ " << this << " add " << value << " @ " << when << endl;
291 Glib::Mutex::Lock lm (lock);
295 ControlEvent cp (when, 0.0);
298 if ((last_rt_insertion_point != events.end()) && ((*last_rt_insertion_point)->when < when) ) {
300 /* we have a previous insertion point, so we should delete
301 everything between it and the position where we are going
302 to insert this point.
305 iterator after = last_rt_insertion_point;
307 if (++after != events.end()) {
308 iterator far = after;
310 while (far != events.end()) {
311 if ((*far)->when > when) {
319 last_rt_insertion_point = where;
321 if((*where)->when == when) {
322 (*where)->value = value;
326 where = events.erase (after, far);
335 iterator previous = last_rt_insertion_point;
338 if (last_rt_insertion_point != events.begin() && (*last_rt_insertion_point)->value == value && (*previous)->value == value) {
339 (*last_rt_insertion_point)->when = when;
346 where = lower_bound (events.begin(), events.end(), &cp, cmp);
348 if (where != events.end()) {
349 if ((*where)->when == when) {
350 (*where)->value = value;
357 last_rt_insertion_point = events.insert (where, point_factory (when, value));
364 maybe_signal_changed ();
368 AutomationList::fast_simple_add (double when, double value)
370 /* to be used only for loading pre-sorted data from saved state */
371 events.insert (events.end(), point_factory (when, value));
374 #undef last_rt_insertion_point
377 AutomationList::add (double when, double value)
379 /* this is for graphical editing */
382 Glib::Mutex::Lock lm (lock);
384 ControlEvent cp (when, 0.0f);
386 iterator insertion_point;
388 for (insertion_point = lower_bound (events.begin(), events.end(), &cp, cmp); insertion_point != events.end(); ++insertion_point) {
390 /* only one point allowed per time point */
392 if ((*insertion_point)->when == when) {
393 (*insertion_point)->value = value;
398 if ((*insertion_point)->when >= when) {
405 events.insert (insertion_point, point_factory (when, value));
406 reposition_for_rt_add (0);
413 maybe_signal_changed ();
417 AutomationList::erase (AutomationList::iterator i)
420 Glib::Mutex::Lock lm (lock);
422 reposition_for_rt_add (0);
425 maybe_signal_changed ();
429 AutomationList::erase (AutomationList::iterator start, AutomationList::iterator end)
432 Glib::Mutex::Lock lm (lock);
433 events.erase (start, end);
434 reposition_for_rt_add (0);
437 maybe_signal_changed ();
441 AutomationList::reset_range (double start, double endt)
446 Glib::Mutex::Lock lm (lock);
448 ControlEvent cp (start, 0.0f);
452 if ((s = lower_bound (events.begin(), events.end(), &cp, cmp)) != events.end()) {
455 e = upper_bound (events.begin(), events.end(), &cp, cmp);
457 for (iterator i = s; i != e; ++i) {
458 (*i)->value = default_value;
468 maybe_signal_changed ();
473 AutomationList::erase_range (double start, double endt)
478 Glib::Mutex::Lock lm (lock);
480 ControlEvent cp (start, 0.0f);
484 if ((s = lower_bound (events.begin(), events.end(), &cp, cmp)) != events.end()) {
486 e = upper_bound (events.begin(), events.end(), &cp, cmp);
488 reposition_for_rt_add (0);
496 maybe_signal_changed ();
501 AutomationList::move_range (iterator start, iterator end, double xdelta, double ydelta)
503 /* note: we assume higher level logic is in place to avoid this
504 reordering the time-order of control events in the list. ie. all
505 points after end are later than (end)->when.
509 Glib::Mutex::Lock lm (lock);
511 while (start != end) {
512 (*start)->when += xdelta;
513 (*start)->value += ydelta;
514 if (isnan ((*start)->value)) {
523 maybe_signal_changed ();
527 AutomationList::modify (iterator iter, double when, double val)
529 /* note: we assume higher level logic is in place to avoid this
530 reordering the time-order of control events in the list. ie. all
531 points after *iter are later than when.
535 Glib::Mutex::Lock lm (lock);
536 (*iter)->when = when;
537 (*iter)->value = val;
544 maybe_signal_changed ();
547 std::pair<AutomationList::iterator,AutomationList::iterator>
548 AutomationList::control_points_adjacent (double xval)
550 Glib::Mutex::Lock lm (lock);
553 ControlEvent cp (xval, 0.0f);
554 std::pair<iterator,iterator> ret;
556 ret.first = events.end();
557 ret.second = events.end();
559 for (i = lower_bound (events.begin(), events.end(), &cp, cmp); i != events.end(); ++i) {
561 if (ret.first == events.end()) {
562 if ((*i)->when >= xval) {
563 if (i != events.begin()) {
572 if ((*i)->when > xval) {
582 AutomationList::freeze ()
588 AutomationList::thaw ()
591 if (changed_when_thawed) {
592 StateChanged(); /* EMIT SIGNAL */
597 AutomationList::set_max_xval (double x)
603 AutomationList::mark_dirty ()
605 lookup_cache.left = -1;
610 AutomationList::truncate_end (double last_coordinate)
613 Glib::Mutex::Lock lm (lock);
614 ControlEvent cp (last_coordinate, 0);
615 list<ControlEvent*>::reverse_iterator i;
618 if (events.empty()) {
622 if (last_coordinate == events.back()->when) {
626 if (last_coordinate > events.back()->when) {
631 iterator foo = events.begin();
634 if (foo == events.end()) {
636 } else if (++foo == events.end()) {
643 /* less than 2 points: add a new point */
644 events.push_back (point_factory (last_coordinate, events.back()->value));
647 /* more than 2 points: check to see if the last 2 values
648 are equal. if so, just move the position of the
649 last point. otherwise, add a new point.
652 iterator penultimate = events.end();
653 --penultimate; /* points at last point */
654 --penultimate; /* points at the penultimate point */
656 if (events.back()->value == (*penultimate)->value) {
657 events.back()->when = last_coordinate;
659 events.push_back (point_factory (last_coordinate, events.back()->value));
667 last_val = unlocked_eval (last_coordinate);
668 last_val = max ((double) min_yval, last_val);
669 last_val = min ((double) max_yval, last_val);
673 /* make i point to the last control point */
677 /* now go backwards, removing control points that are
678 beyond the new last coordinate.
681 uint32_t sz = events.size();
683 while (i != events.rend() && sz > 2) {
684 list<ControlEvent*>::reverse_iterator tmp;
689 if ((*i)->when < last_coordinate) {
693 events.erase (i.base());
699 events.back()->when = last_coordinate;
700 events.back()->value = last_val;
703 reposition_for_rt_add (0);
707 maybe_signal_changed ();
711 AutomationList::truncate_start (double overall_length)
714 Glib::Mutex::Lock lm (lock);
715 AutomationList::iterator i;
716 double first_legal_value;
717 double first_legal_coordinate;
719 if (events.empty()) {
720 fatal << _("programming error:")
721 << "AutomationList::truncate_start() called on an empty list"
727 if (overall_length == events.back()->when) {
728 /* no change in overall length */
732 if (overall_length > events.back()->when) {
734 /* growing at front: duplicate first point. shift all others */
736 double shift = overall_length - events.back()->when;
739 for (np = 0, i = events.begin(); i != events.end(); ++i, ++np) {
745 /* less than 2 points: add a new point */
746 events.push_front (point_factory (0, events.front()->value));
750 /* more than 2 points: check to see if the first 2 values
751 are equal. if so, just move the position of the
752 first point. otherwise, add a new point.
755 iterator second = events.begin();
756 ++second; /* points at the second point */
758 if (events.front()->value == (*second)->value) {
759 /* first segment is flat, just move start point back to zero */
760 events.front()->when = 0;
762 /* leave non-flat segment in place, add a new leading point. */
763 events.push_front (point_factory (0, events.front()->value));
769 /* shrinking at front */
771 first_legal_coordinate = events.back()->when - overall_length;
772 first_legal_value = unlocked_eval (first_legal_coordinate);
773 first_legal_value = max (min_yval, first_legal_value);
774 first_legal_value = min (max_yval, first_legal_value);
776 /* remove all events earlier than the new "front" */
780 while (i != events.end() && !events.empty()) {
781 list<ControlEvent*>::iterator tmp;
786 if ((*i)->when > first_legal_coordinate) {
796 /* shift all remaining points left to keep their same
800 for (i = events.begin(); i != events.end(); ++i) {
801 (*i)->when -= first_legal_coordinate;
804 /* add a new point for the interpolated new value */
806 events.push_front (point_factory (0, first_legal_value));
809 reposition_for_rt_add (0);
814 maybe_signal_changed ();
818 AutomationList::unlocked_eval (double x)
820 return shared_eval (x);
824 AutomationList::shared_eval (double x)
826 pair<AutomationEventList::iterator,AutomationEventList::iterator> range;
832 npoints = events.size();
836 return default_value;
839 if (x >= events.front()->when) {
840 return events.front()->value;
842 // return default_value;
843 return events.front()->value;
847 if (x >= events.back()->when) {
848 return events.back()->value;
849 } else if (x == events.front()->when) {
850 return events.front()->value;
851 } else if (x < events.front()->when) {
852 // return default_value;
853 return events.front()->value;
856 lpos = events.front()->when;
857 lval = events.front()->value;
858 upos = events.back()->when;
859 uval = events.back()->value;
861 /* linear interpolation betweeen the two points
864 fraction = (double) (x - lpos) / (double) (upos - lpos);
865 return lval + (fraction * (uval - lval));
869 if (x >= events.back()->when) {
870 return events.back()->value;
871 } else if (x == events.front()->when) {
872 return events.front()->value;
873 } else if (x < events.front()->when) {
874 // return default_value;
875 return events.front()->value;
878 return multipoint_eval (x);
884 AutomationList::multipoint_eval (double x)
886 pair<AutomationList::iterator,AutomationList::iterator> range;
891 /* only do the range lookup if x is in a different range than last time
892 this was called (or if the lookup cache has been marked "dirty" (left<0)
895 if ((lookup_cache.left < 0) ||
896 ((lookup_cache.left > x) ||
897 (lookup_cache.range.first == events.end()) ||
898 ((*lookup_cache.range.second)->when < x))) {
900 ControlEvent cp (x, 0);
903 lookup_cache.range = equal_range (events.begin(), events.end(), &cp, cmp);
906 range = lookup_cache.range;
908 if (range.first == range.second) {
910 /* x does not exist within the list as a control point */
912 lookup_cache.left = x;
914 if (range.first != events.begin()) {
916 lpos = (*range.first)->when;
917 lval = (*range.first)->value;
919 /* we're before the first point */
920 // return default_value;
921 return events.front()->value;
924 if (range.second == events.end()) {
925 /* we're after the last point */
926 return events.back()->value;
929 upos = (*range.second)->when;
930 uval = (*range.second)->value;
932 /* linear interpolation betweeen the two points
936 fraction = (double) (x - lpos) / (double) (upos - lpos);
937 return lval + (fraction * (uval - lval));
941 /* x is a control point in the data */
942 lookup_cache.left = -1;
943 return (*range.first)->value;
947 AutomationList::cut (iterator start, iterator end)
949 AutomationList* nal = new AutomationList (default_value);
952 Glib::Mutex::Lock lm (lock);
954 for (iterator x = start; x != end; ) {
960 nal->events.push_back (point_factory (**x));
963 reposition_for_rt_add (0);
971 maybe_signal_changed ();
977 AutomationList::cut_copy_clear (double start, double end, int op)
979 AutomationList* nal = new AutomationList (default_value);
981 ControlEvent cp (start, 0.0);
983 bool changed = false;
986 Glib::Mutex::Lock lm (lock);
988 if ((s = lower_bound (events.begin(), events.end(), &cp, cmp)) == events.end()) {
993 e = upper_bound (events.begin(), events.end(), &cp, cmp);
995 if (op != 2 && (*s)->when != start) {
996 nal->events.push_back (point_factory (0, unlocked_eval (start)));
999 for (iterator x = s; x != e; ) {
1007 /* adjust new points to be relative to start, which
1008 has been set to zero.
1012 nal->events.push_back (point_factory ((*x)->when - start, (*x)->value));
1022 if (op != 2 && nal->events.back()->when != end - start) {
1023 nal->events.push_back (point_factory (end - start, unlocked_eval (end)));
1027 reposition_for_rt_add (0);
1033 maybe_signal_changed ();
1040 AutomationList::copy (iterator start, iterator end)
1042 AutomationList* nal = new AutomationList (default_value);
1045 Glib::Mutex::Lock lm (lock);
1047 for (iterator x = start; x != end; ) {
1053 nal->events.push_back (point_factory (**x));
1063 AutomationList::cut (double start, double end)
1065 return cut_copy_clear (start, end, 0);
1069 AutomationList::copy (double start, double end)
1071 return cut_copy_clear (start, end, 1);
1075 AutomationList::clear (double start, double end)
1077 (void) cut_copy_clear (start, end, 2);
1081 AutomationList::paste (AutomationList& alist, double pos, float times)
1083 if (alist.events.empty()) {
1088 Glib::Mutex::Lock lm (lock);
1092 ControlEvent cp (pos, 0.0);
1095 where = upper_bound (events.begin(), events.end(), &cp, cmp);
1097 for (iterator i = alist.begin();i != alist.end(); ++i) {
1098 events.insert (where, point_factory( (*i)->when+pos,( *i)->value));
1099 end = (*i)->when + pos;
1103 /* move all points after the insertion along the timeline by
1107 while (where != events.end()) {
1109 if ((*where)->when <= end) {
1112 events.erase(where);
1120 reposition_for_rt_add (0);
1124 maybe_signal_changed ();
1129 AutomationList::point_factory (double when, double val) const
1131 return new ControlEvent (when, val);
1135 AutomationList::point_factory (const ControlEvent& other) const
1137 return new ControlEvent (other);
1141 AutomationList::get_state ()
1143 return state (true);
1147 AutomationList::state (bool full)
1149 XMLNode* root = new XMLNode (X_("AutomationList"));
1151 LocaleGuard lg (X_("POSIX"));
1153 root->add_property ("id", _id.to_s());
1155 snprintf (buf, sizeof (buf), "%.12g", default_value);
1156 root->add_property ("default", buf);
1157 snprintf (buf, sizeof (buf), "%.12g", min_yval);
1158 root->add_property ("min_yval", buf);
1159 snprintf (buf, sizeof (buf), "%.12g", max_yval);
1160 root->add_property ("max_yval", buf);
1161 snprintf (buf, sizeof (buf), "%.12g", max_xval);
1162 root->add_property ("max_xval", buf);
1165 root->add_property ("state", auto_state_to_string (_state));
1167 /* never save anything but Off for automation state to a template */
1168 root->add_property ("state", auto_state_to_string (Off));
1171 root->add_property ("style", auto_style_to_string (_style));
1173 if (!events.empty()) {
1174 root->add_child_nocopy (serialize_events());
1181 AutomationList::serialize_events ()
1183 XMLNode* node = new XMLNode (X_("events"));
1186 for (iterator xx = events.begin(); xx != events.end(); ++xx) {
1187 str << (double) (*xx)->when;
1189 str <<(double) (*xx)->value;
1193 /* XML is a bit wierd */
1195 XMLNode* content_node = new XMLNode (X_("foo")); /* it gets renamed by libxml when we set content */
1196 content_node->set_content (str.str());
1198 node->add_child_nocopy (*content_node);
1204 AutomationList::deserialize_events (const XMLNode& node)
1206 if (node.children().empty()) {
1210 XMLNode* content_node = node.children().front();
1212 if (content_node->content().empty()) {
1219 stringstream str (content_node->content());
1235 fast_simple_add (x, y);
1240 error << _("automation list: cannot load coordinates from XML, all points ignored") << endmsg;
1243 reposition_for_rt_add (0);
1244 maybe_signal_changed ();
1253 AutomationList::set_state (const XMLNode& node)
1255 XMLNodeList nlist = node.children();
1257 XMLNodeIterator niter;
1258 const XMLProperty* prop;
1260 if (node.name() == X_("events")) {
1261 /* partial state setting*/
1262 return deserialize_events (node);
1265 if (node.name() == X_("Envelope") || node.name() == X_("FadeOut") || node.name() == X_("FadeIn")) {
1267 if ((nsos = node.child (X_("AutomationList")))) {
1268 /* new school in old school clothing */
1269 return set_state (*nsos);
1274 const XMLNodeList& elist = node.children();
1275 XMLNodeConstIterator i;
1283 for (i = elist.begin(); i != elist.end(); ++i) {
1285 if ((prop = (*i)->property ("x")) == 0) {
1286 error << _("automation list: no x-coordinate stored for control point (point ignored)") << endmsg;
1289 x = atoi (prop->value().c_str());
1291 if ((prop = (*i)->property ("y")) == 0) {
1292 error << _("automation list: no y-coordinate stored for control point (point ignored)") << endmsg;
1295 y = atof (prop->value().c_str());
1297 fast_simple_add (x, y);
1305 if (node.name() != X_("AutomationList") ) {
1306 error << string_compose (_("AutomationList: passed XML node called %1, not \"AutomationList\" - ignored"), node.name()) << endmsg;
1310 if ((prop = node.property ("id")) != 0) {
1311 _id = prop->value ();
1312 /* update session AL list */
1313 AutomationListCreated(this);
1316 if ((prop = node.property (X_("default"))) != 0){
1317 default_value = atof (prop->value());
1319 default_value = 0.0;
1322 if ((prop = node.property (X_("style"))) != 0) {
1323 _style = string_to_auto_style (prop->value());
1328 if ((prop = node.property (X_("state"))) != 0) {
1329 _state = string_to_auto_state (prop->value());
1334 if ((prop = node.property (X_("min_yval"))) != 0) {
1335 min_yval = atof (prop->value ());
1340 if ((prop = node.property (X_("max_yval"))) != 0) {
1341 max_yval = atof (prop->value ());
1346 if ((prop = node.property (X_("max_xval"))) != 0) {
1347 max_xval = atof (prop->value ());
1349 max_xval = 0; // means "no limit ;
1352 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1353 if ((*niter)->name() == X_("events")) {
1354 deserialize_events (*(*niter));