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, bool with_state)
53 changed_when_thawed = false;
57 no_state = with_state;
60 max_xval = 0; // means "no limit"
61 default_value = defval;
63 rt_insertion_point = events.end();
64 lookup_cache.left = -1;
65 lookup_cache.range.first = events.end();
67 AutomationListCreated(this);
70 AutomationList::AutomationList (const AutomationList& other)
73 changed_when_thawed = false;
74 _style = other._style;
75 min_yval = other.min_yval;
76 max_yval = other.max_yval;
77 max_xval = other.max_xval;
78 default_value = other.default_value;
79 _state = other._state;
80 _touching = other._touching;
82 rt_insertion_point = events.end();
83 no_state = other.no_state;
84 lookup_cache.left = -1;
85 lookup_cache.range.first = events.end();
87 for (const_iterator i = other.events.begin(); i != other.events.end(); ++i) {
88 /* we have to use other point_factory() because
89 its virtual and we're in a constructor.
91 events.push_back (other.point_factory (**i));
95 AutomationListCreated(this);
98 AutomationList::AutomationList (const AutomationList& other, double start, double end)
101 changed_when_thawed = false;
102 _style = other._style;
103 min_yval = other.min_yval;
104 max_yval = other.max_yval;
105 max_xval = other.max_xval;
106 default_value = other.default_value;
107 _state = other._state;
108 _touching = other._touching;
110 rt_insertion_point = events.end();
111 no_state = other.no_state;
112 lookup_cache.left = -1;
113 lookup_cache.range.first = events.end();
115 /* now grab the relevant points, and shift them back if necessary */
117 AutomationList* section = const_cast<AutomationList*>(&other)->copy (start, end);
119 if (!section->empty()) {
120 for (AutomationList::iterator i = section->begin(); i != section->end(); ++i) {
121 events.push_back (other.point_factory ((*i)->when, (*i)->value));
128 AutomationListCreated(this);
131 AutomationList::~AutomationList()
135 for (AutomationEventList::iterator x = events.begin(); x != events.end(); ++x) {
141 AutomationList::operator== (const AutomationList& other)
143 return events == other.events;
147 AutomationList::operator= (const AutomationList& other)
149 if (this != &other) {
153 for (const_iterator i = other.events.begin(); i != other.events.end(); ++i) {
154 events.push_back (point_factory (**i));
157 min_yval = other.min_yval;
158 max_yval = other.max_yval;
159 max_xval = other.max_xval;
160 default_value = other.default_value;
163 maybe_signal_changed ();
170 AutomationList::maybe_signal_changed ()
175 changed_when_thawed = true;
177 StateChanged (Change (0));
182 AutomationList::set_automation_state (AutoState s)
186 automation_state_changed (); /* EMIT SIGNAL */
191 AutomationList::set_automation_style (AutoStyle s)
195 automation_style_changed (); /* EMIT SIGNAL */
200 AutomationList::start_touch ()
207 AutomationList::stop_touch ()
214 AutomationList::clear ()
217 Glib::Mutex::Lock lm (lock);
222 maybe_signal_changed ();
226 AutomationList::x_scale (double factor)
228 Glib::Mutex::Lock lm (lock);
233 AutomationList::extend_to (double when)
235 Glib::Mutex::Lock lm (lock);
236 if (events.empty() || events.back()->when == when) {
239 double factor = when / events.back()->when;
244 void AutomationList::_x_scale (double factor)
246 for (AutomationList::iterator i = events.begin(); i != events.end(); ++i) {
247 (*i)->when = floor ((*i)->when * factor);
254 AutomationList::reposition_for_rt_add (double when)
256 rt_insertion_point = events.end();
259 #define last_rt_insertion_point rt_insertion_point
262 AutomationList::rt_add (double when, double value)
264 /* this is for automation recording */
266 if ((_state & Touch) && !_touching) {
270 // cerr << "RT: alist @ " << this << " add " << value << " @ " << when << endl;
273 Glib::Mutex::Lock lm (lock);
277 ControlEvent cp (when, 0.0);
280 if ((last_rt_insertion_point != events.end()) && ((*last_rt_insertion_point)->when < when) ) {
282 /* we have a previous insertion point, so we should delete
283 everything between it and the position where we are going
284 to insert this point.
287 iterator after = last_rt_insertion_point;
289 if (++after != events.end()) {
290 iterator far = after;
292 while (far != events.end()) {
293 if ((*far)->when > when) {
301 last_rt_insertion_point = where;
303 if((*where)->when == when) {
304 (*where)->value = value;
308 where = events.erase (after, far);
317 iterator previous = last_rt_insertion_point;
320 if (last_rt_insertion_point != events.begin() && (*last_rt_insertion_point)->value == value && (*previous)->value == value) {
321 (*last_rt_insertion_point)->when = when;
328 where = lower_bound (events.begin(), events.end(), &cp, cmp);
330 if (where != events.end()) {
331 if ((*where)->when == when) {
332 (*where)->value = value;
339 last_rt_insertion_point = events.insert (where, point_factory (when, value));
346 maybe_signal_changed ();
349 #undef last_rt_insertion_point
352 AutomationList::add (double when, double value)
354 /* this is for graphical editing and loading data from storage */
357 Glib::Mutex::Lock lm (lock);
359 ControlEvent cp (when, 0.0f);
361 iterator insertion_point;
363 for (insertion_point = lower_bound (events.begin(), events.end(), &cp, cmp); insertion_point != events.end(); ++insertion_point) {
365 /* only one point allowed per time point */
367 if ((*insertion_point)->when == when) {
368 (*insertion_point)->value = value;
373 if ((*insertion_point)->when >= when) {
380 events.insert (insertion_point, point_factory (when, value));
381 reposition_for_rt_add (0);
388 maybe_signal_changed ();
392 AutomationList::erase (AutomationList::iterator i)
395 Glib::Mutex::Lock lm (lock);
397 reposition_for_rt_add (0);
400 save_state (_("removed event"));
405 maybe_signal_changed ();
409 AutomationList::erase (AutomationList::iterator start, AutomationList::iterator end)
412 Glib::Mutex::Lock lm (lock);
413 events.erase (start, end);
414 reposition_for_rt_add (0);
417 maybe_signal_changed ();
421 AutomationList::reset_range (double start, double endt)
426 Glib::Mutex::Lock lm (lock);
428 ControlEvent cp (start, 0.0f);
432 if ((s = lower_bound (events.begin(), events.end(), &cp, cmp)) != events.end()) {
435 e = upper_bound (events.begin(), events.end(), &cp, cmp);
437 for (iterator i = s; i != e; ++i) {
438 (*i)->value = default_value;
448 maybe_signal_changed ();
453 AutomationList::erase_range (double start, double endt)
458 Glib::Mutex::Lock lm (lock);
460 ControlEvent cp (start, 0.0f);
464 if ((s = lower_bound (events.begin(), events.end(), &cp, cmp)) != events.end()) {
466 e = upper_bound (events.begin(), events.end(), &cp, cmp);
468 reposition_for_rt_add (0);
476 maybe_signal_changed ();
481 AutomationList::move_range (iterator start, iterator end, double xdelta, double ydelta)
483 /* note: we assume higher level logic is in place to avoid this
484 reordering the time-order of control events in the list. ie. all
485 points after end are later than (end)->when.
489 Glib::Mutex::Lock lm (lock);
491 while (start != end) {
492 (*start)->when += xdelta;
493 (*start)->value += ydelta;
500 maybe_signal_changed ();
504 AutomationList::modify (iterator iter, double when, double val)
506 /* note: we assume higher level logic is in place to avoid this
507 reordering the time-order of control events in the list. ie. all
508 points after *iter are later than when.
512 Glib::Mutex::Lock lm (lock);
513 (*iter)->when = when;
514 (*iter)->value = val;
518 maybe_signal_changed ();
521 std::pair<AutomationList::iterator,AutomationList::iterator>
522 AutomationList::control_points_adjacent (double xval)
524 Glib::Mutex::Lock lm (lock);
527 ControlEvent cp (xval, 0.0f);
528 std::pair<iterator,iterator> ret;
530 ret.first = events.end();
531 ret.second = events.end();
533 for (i = lower_bound (events.begin(), events.end(), &cp, cmp); i != events.end(); ++i) {
535 if (ret.first == events.end()) {
536 if ((*i)->when >= xval) {
537 if (i != events.begin()) {
546 if ((*i)->when > xval) {
556 AutomationList::freeze ()
562 AutomationList::thaw ()
565 if (changed_when_thawed) {
566 StateChanged(Change(0)); /* EMIT SIGNAL */
571 AutomationList::set_max_xval (double x)
577 AutomationList::mark_dirty ()
579 lookup_cache.left = -1;
584 AutomationList::truncate_end (double last_coordinate)
587 Glib::Mutex::Lock lm (lock);
588 ControlEvent cp (last_coordinate, 0);
589 list<ControlEvent*>::reverse_iterator i;
592 if (events.empty()) {
593 fatal << _("programming error:")
594 << "AutomationList::truncate_end() called on an empty list"
600 if (last_coordinate == events.back()->when) {
604 if (last_coordinate > events.back()->when) {
609 iterator foo = events.begin();
612 if (foo == events.end()) {
614 } else if (++foo == events.end()) {
621 /* less than 2 points: add a new point */
622 events.push_back (point_factory (last_coordinate, events.back()->value));
625 /* more than 2 points: check to see if the last 2 values
626 are equal. if so, just move the position of the
627 last point. otherwise, add a new point.
630 iterator penultimate = events.end();
631 --penultimate; /* points at last point */
632 --penultimate; /* points at the penultimate point */
634 if (events.back()->value == (*penultimate)->value) {
635 events.back()->when = last_coordinate;
637 events.push_back (point_factory (last_coordinate, events.back()->value));
645 last_val = unlocked_eval (last_coordinate);
646 last_val = max ((double) min_yval, last_val);
647 last_val = min ((double) max_yval, last_val);
651 /* make i point to the last control point */
655 /* now go backwards, removing control points that are
656 beyond the new last coordinate.
659 uint32_t sz = events.size();
661 while (i != events.rend() && sz > 2) {
662 list<ControlEvent*>::reverse_iterator tmp;
667 if ((*i)->when < last_coordinate) {
671 events.erase (i.base());
677 events.back()->when = last_coordinate;
678 events.back()->value = last_val;
681 reposition_for_rt_add (0);
685 maybe_signal_changed ();
689 AutomationList::truncate_start (double overall_length)
692 Glib::Mutex::Lock lm (lock);
693 AutomationList::iterator i;
694 double first_legal_value;
695 double first_legal_coordinate;
697 if (events.empty()) {
698 fatal << _("programming error:")
699 << "AutomationList::truncate_start() called on an empty list"
705 if (overall_length == events.back()->when) {
706 /* no change in overall length */
710 if (overall_length > events.back()->when) {
712 /* growing at front: duplicate first point. shift all others */
714 double shift = overall_length - events.back()->when;
717 for (np = 0, i = events.begin(); i != events.end(); ++i, ++np) {
723 /* less than 2 points: add a new point */
724 events.push_front (point_factory (0, events.front()->value));
728 /* more than 2 points: check to see if the first 2 values
729 are equal. if so, just move the position of the
730 first point. otherwise, add a new point.
733 iterator second = events.begin();
734 ++second; /* points at the second point */
736 if (events.front()->value == (*second)->value) {
737 /* first segment is flat, just move start point back to zero */
738 events.front()->when = 0;
740 /* leave non-flat segment in place, add a new leading point. */
741 events.push_front (point_factory (0, events.front()->value));
747 /* shrinking at front */
749 first_legal_coordinate = events.back()->when - overall_length;
750 first_legal_value = unlocked_eval (first_legal_coordinate);
751 first_legal_value = max (min_yval, first_legal_value);
752 first_legal_value = min (max_yval, first_legal_value);
754 /* remove all events earlier than the new "front" */
758 while (i != events.end() && !events.empty()) {
759 list<ControlEvent*>::iterator tmp;
764 if ((*i)->when > first_legal_coordinate) {
774 /* shift all remaining points left to keep their same
778 for (i = events.begin(); i != events.end(); ++i) {
779 (*i)->when -= first_legal_coordinate;
782 /* add a new point for the interpolated new value */
784 events.push_front (point_factory (0, first_legal_value));
787 reposition_for_rt_add (0);
792 maybe_signal_changed ();
796 AutomationList::unlocked_eval (double x)
798 return shared_eval (x);
802 AutomationList::shared_eval (double x)
804 pair<AutomationEventList::iterator,AutomationEventList::iterator> range;
810 npoints = events.size();
814 return default_value;
817 if (x >= events.front()->when) {
818 return events.front()->value;
820 // return default_value;
821 return events.front()->value;
825 if (x >= events.back()->when) {
826 return events.back()->value;
827 } else if (x == events.front()->when) {
828 return events.front()->value;
829 } else if (x < events.front()->when) {
830 // return default_value;
831 return events.front()->value;
834 lpos = events.front()->when;
835 lval = events.front()->value;
836 upos = events.back()->when;
837 uval = events.back()->value;
839 /* linear interpolation betweeen the two points
842 fraction = (double) (x - lpos) / (double) (upos - lpos);
843 return lval + (fraction * (uval - lval));
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 return multipoint_eval (x);
862 AutomationList::multipoint_eval (double x)
864 pair<AutomationList::iterator,AutomationList::iterator> range;
869 /* only do the range lookup if x is in a different range than last time
870 this was called (or if the lookup cache has been marked "dirty" (left<0)
873 if ((lookup_cache.left < 0) ||
874 ((lookup_cache.left > x) ||
875 (lookup_cache.range.first == events.end()) ||
876 ((*lookup_cache.range.second)->when < x))) {
878 ControlEvent cp (x, 0);
881 lookup_cache.range = equal_range (events.begin(), events.end(), &cp, cmp);
884 range = lookup_cache.range;
886 if (range.first == range.second) {
888 /* x does not exist within the list as a control point */
890 lookup_cache.left = x;
892 if (range.first != events.begin()) {
894 lpos = (*range.first)->when;
895 lval = (*range.first)->value;
897 /* we're before the first point */
898 // return default_value;
899 return events.front()->value;
902 if (range.second == events.end()) {
903 /* we're after the last point */
904 return events.back()->value;
907 upos = (*range.second)->when;
908 uval = (*range.second)->value;
910 /* linear interpolation betweeen the two points
914 fraction = (double) (x - lpos) / (double) (upos - lpos);
915 return lval + (fraction * (uval - lval));
919 /* x is a control point in the data */
920 lookup_cache.left = -1;
921 return (*range.first)->value;
925 AutomationList::cut (iterator start, iterator end)
927 AutomationList* nal = new AutomationList (default_value);
930 Glib::Mutex::Lock lm (lock);
932 for (iterator x = start; x != end; ) {
938 nal->events.push_back (point_factory (**x));
941 reposition_for_rt_add (0);
949 maybe_signal_changed ();
955 AutomationList::cut_copy_clear (double start, double end, int op)
957 AutomationList* nal = new AutomationList (default_value);
959 ControlEvent cp (start, 0.0);
961 bool changed = false;
964 Glib::Mutex::Lock lm (lock);
966 if ((s = lower_bound (events.begin(), events.end(), &cp, cmp)) == events.end()) {
971 e = upper_bound (events.begin(), events.end(), &cp, cmp);
973 if (op != 2 && (*s)->when != start) {
974 nal->events.push_back (point_factory (0, unlocked_eval (start)));
977 for (iterator x = s; x != e; ) {
985 /* adjust new points to be relative to start, which
986 has been set to zero.
990 nal->events.push_back (point_factory ((*x)->when - start, (*x)->value));
1000 if (op != 2 && nal->events.back()->when != end - start) {
1001 nal->events.push_back (point_factory (end - start, unlocked_eval (end)));
1005 reposition_for_rt_add (0);
1011 maybe_signal_changed ();
1018 AutomationList::copy (iterator start, iterator end)
1020 AutomationList* nal = new AutomationList (default_value);
1023 Glib::Mutex::Lock lm (lock);
1025 for (iterator x = start; x != end; ) {
1031 nal->events.push_back (point_factory (**x));
1041 AutomationList::cut (double start, double end)
1043 return cut_copy_clear (start, end, 0);
1047 AutomationList::copy (double start, double end)
1049 return cut_copy_clear (start, end, 1);
1053 AutomationList::clear (double start, double end)
1055 (void) cut_copy_clear (start, end, 2);
1059 AutomationList::paste (AutomationList& alist, double pos, float times)
1061 if (alist.events.empty()) {
1066 Glib::Mutex::Lock lm (lock);
1070 ControlEvent cp (pos, 0.0);
1073 where = upper_bound (events.begin(), events.end(), &cp, cmp);
1075 for (iterator i = alist.begin();i != alist.end(); ++i) {
1076 events.insert (where, point_factory( (*i)->when+pos,( *i)->value));
1077 end = (*i)->when + pos;
1081 /* move all points after the insertion along the timeline by
1085 while (where != events.end()) {
1087 if ((*where)->when <= end) {
1090 events.erase(where);
1098 reposition_for_rt_add (0);
1102 maybe_signal_changed ();
1107 AutomationList::point_factory (double when, double val) const
1109 return new ControlEvent (when, val);
1113 AutomationList::point_factory (const ControlEvent& other) const
1115 return new ControlEvent (other);
1119 AutomationList::get_state ()
1122 XMLNode* node = new XMLNode (X_("events"));
1125 if (events.empty()) {
1129 for (xx = events.begin(); xx != events.end(); ++xx) {
1130 str << (double) (*xx)->when;
1132 str <<(double) (*xx)->value;
1136 node->add_content (str.str());
1142 AutomationList::set_state (const XMLNode& node)
1144 if (node.name() != X_("events")) {
1145 warning << _("automation list: passed XML node not called \"events\" - ignored.") << endmsg;
1152 if (!node.content().empty()) {
1154 stringstream str (node.content());
1176 error << _("automation list: cannot load coordinates from XML, all points ignored") << endmsg;