1 /* This file is part of Evoral.
2 * Copyright (C) 2008 David Robillard <http://drobilla.net>
3 * Copyright (C) 2000-2008 Paul Davis
5 * Evoral is free software; you can redistribute it and/or modify it under the
6 * terms of the GNU General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option) any later
10 * Evoral is distributed in the hope that it will be useful, but WITHOUT ANY
11 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 // 'std::isnan()' is not available in MSVC.
25 #define isnan_local(val) (bool)_isnan((double)val)
27 #define isnan_local std::isnan
35 #include "evoral/ControlList.hpp"
36 #include "evoral/Curve.hpp"
37 #include "evoral/ParameterDescriptor.hpp"
38 #include "evoral/TypeMap.hpp"
40 #include "pbd/compose.h"
41 #include "pbd/debug.h"
48 inline bool event_time_less_than (ControlEvent* a, ControlEvent* b)
50 return a->when < b->when;
53 ControlList::ControlList (const Parameter& id, const ParameterDescriptor& desc)
58 _interpolation = desc.toggled ? Discrete : Linear;
60 _changed_when_thawed = false;
61 _min_yval = desc.lower;
62 _max_yval = desc.upper;
63 _default_value = desc.normal;
64 _lookup_cache.left = -1;
65 _lookup_cache.range.first = _events.end();
66 _lookup_cache.range.second = _events.end();
67 _search_cache.left = -1;
68 _search_cache.first = _events.end();
69 _sort_pending = false;
70 new_write_pass = true;
71 _in_write_pass = false;
72 did_write_during_pass = false;
74 most_recent_insert_iterator = _events.end();
77 ControlList::ControlList (const ControlList& other)
78 : _parameter(other._parameter)
80 , _interpolation(other._interpolation)
84 _changed_when_thawed = false;
85 _min_yval = other._min_yval;
86 _max_yval = other._max_yval;
87 _default_value = other._default_value;
88 _lookup_cache.range.first = _events.end();
89 _lookup_cache.range.second = _events.end();
90 _search_cache.first = _events.end();
91 _sort_pending = false;
92 new_write_pass = true;
93 _in_write_pass = false;
94 did_write_during_pass = false;
96 most_recent_insert_iterator = _events.end();
103 ControlList::ControlList (const ControlList& other, double start, double end)
104 : _parameter(other._parameter)
106 , _interpolation(other._interpolation)
110 _changed_when_thawed = false;
111 _min_yval = other._min_yval;
112 _max_yval = other._max_yval;
113 _default_value = other._default_value;
114 _lookup_cache.range.first = _events.end();
115 _lookup_cache.range.second = _events.end();
116 _search_cache.first = _events.end();
117 _sort_pending = false;
119 /* now grab the relevant points, and shift them back if necessary */
121 boost::shared_ptr<ControlList> section = const_cast<ControlList*>(&other)->copy (start, end);
123 if (!section->empty()) {
124 copy_events (*(section.get()));
127 new_write_pass = false;
128 _in_write_pass = false;
129 did_write_during_pass = false;
130 insert_position = -1;
131 most_recent_insert_iterator = _events.end();
136 ControlList::~ControlList()
138 for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
145 boost::shared_ptr<ControlList>
146 ControlList::create(const Parameter& id, const ParameterDescriptor& desc)
148 return boost::shared_ptr<ControlList>(new ControlList(id, desc));
152 ControlList::operator== (const ControlList& other)
154 return _events == other._events;
158 ControlList::operator= (const ControlList& other)
160 if (this != &other) {
162 _min_yval = other._min_yval;
163 _max_yval = other._max_yval;
166 _interpolation = other._interpolation;
167 _default_value = other._default_value;
176 ControlList::copy_events (const ControlList& other)
179 Glib::Threads::Mutex::Lock lm (_lock);
181 for (const_iterator i = other.begin(); i != other.end(); ++i) {
182 _events.push_back (new ControlEvent ((*i)->when, (*i)->value));
184 unlocked_invalidate_insert_iterator ();
187 maybe_signal_changed ();
191 ControlList::create_curve()
193 _curve = new Curve(*this);
197 ControlList::destroy_curve()
204 ControlList::maybe_signal_changed ()
209 _changed_when_thawed = true;
214 ControlList::clear ()
217 Glib::Threads::Mutex::Lock lm (_lock);
219 unlocked_invalidate_insert_iterator ();
223 maybe_signal_changed ();
227 ControlList::x_scale (double factor)
229 Glib::Threads::Mutex::Lock lm (_lock);
234 ControlList::extend_to (double when)
236 Glib::Threads::Mutex::Lock lm (_lock);
237 if (_events.empty() || _events.back()->when == when) {
240 double factor = when / _events.back()->when;
246 ControlList::_x_scale (double factor)
248 for (iterator i = _events.begin(); i != _events.end(); ++i) {
249 (*i)->when *= factor;
255 struct ControlEventTimeComparator {
256 bool operator() (ControlEvent* a, ControlEvent* b) {
257 return a->when < b->when;
262 ControlList::thin (double thinning_factor)
264 if (thinning_factor == 0.0 || _desc.toggled) {
268 bool changed = false;
271 Glib::Threads::Mutex::Lock lm (_lock);
273 ControlEvent* prevprev = 0;
274 ControlEvent* cur = 0;
275 ControlEvent* prev = 0;
279 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 thin from %2 events\n", this, _events.size()));
281 for (iterator i = _events.begin(); i != _events.end(); ++i) {
288 /* compute the area of the triangle formed by 3 points
291 double area = fabs ((prevprev->when * (prev->value - cur->value)) +
292 (prev->when * (cur->value - prevprev->value)) +
293 (cur->when * (prevprev->value - prev->value)));
295 if (area < thinning_factor) {
296 iterator tmp = pprev;
298 /* pprev will change to current
299 i is incremented to the next event
315 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 thin => %2 events\n", this, _events.size()));
318 unlocked_invalidate_insert_iterator ();
324 maybe_signal_changed ();
329 ControlList::fast_simple_add (double when, double value)
331 Glib::Threads::Mutex::Lock lm (_lock);
332 /* to be used only for loading pre-sorted data from saved state */
333 _events.insert (_events.end(), new ControlEvent (when, value));
334 assert(_events.back());
340 ControlList::invalidate_insert_iterator ()
342 Glib::Threads::Mutex::Lock lm (_lock);
343 unlocked_invalidate_insert_iterator ();
347 ControlList::unlocked_invalidate_insert_iterator ()
349 most_recent_insert_iterator = _events.end();
353 ControlList::start_write_pass (double when)
355 Glib::Threads::Mutex::Lock lm (_lock);
357 DEBUG_TRACE (DEBUG::ControlList, string_compose ("%1: setup write pass @ %2\n", this, when));
359 new_write_pass = true;
360 did_write_during_pass = false;
361 insert_position = when;
363 /* leave the insert iterator invalid, so that we will do the lookup
364 of where it should be in a "lazy" way - deferring it until
365 we actually add the first point (which may never happen).
368 unlocked_invalidate_insert_iterator ();
372 ControlList::write_pass_finished (double /*when*/, double thinning_factor)
374 DEBUG_TRACE (DEBUG::ControlList, "write pass finished\n");
376 if (did_write_during_pass) {
377 thin (thinning_factor);
378 did_write_during_pass = false;
380 new_write_pass = true;
381 _in_write_pass = false;
385 ControlList::set_in_write_pass (bool yn, bool add_point, double when)
387 DEBUG_TRACE (DEBUG::ControlList, string_compose ("now in write pass @ %1, add point ? %2\n", when, add_point));
391 if (yn && add_point) {
392 add_guard_point (when);
397 ControlList::add_guard_point (double when)
399 ControlEvent cp (when, 0.0);
400 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
402 double eval_value = unlocked_eval (insert_position);
404 if (most_recent_insert_iterator == _events.end()) {
406 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert iterator at end, adding eval-value there %2\n", this, eval_value));
407 _events.push_back (new ControlEvent (when, eval_value));
408 /* leave insert iterator at the end */
410 } else if ((*most_recent_insert_iterator)->when == when) {
412 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert iterator at existing point, setting eval-value there %2\n", this, eval_value));
414 /* most_recent_insert_iterator points to a control event
415 already at the insert position, so there is
420 advance most_recent_insert_iterator so that the "real"
421 insert occurs in the right place, since it
422 points to the control event just inserted.
425 ++most_recent_insert_iterator;
428 /* insert a new control event at the right spot
431 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert eval-value %2 just before iterator @ %3\n",
432 this, eval_value, (*most_recent_insert_iterator)->when));
434 most_recent_insert_iterator = _events.insert (most_recent_insert_iterator, new ControlEvent (when, eval_value));
436 /* advance most_recent_insert_iterator so that the "real"
437 * insert occurs in the right place, since it
438 * points to the control event just inserted.
441 ++most_recent_insert_iterator;
444 /* don't do this again till the next write pass */
446 new_write_pass = false;
450 ControlList::in_write_pass () const
452 return _in_write_pass;
456 ControlList::editor_add (double when, double value)
458 /* this is for making changes from a graphical line editor
461 if (_events.empty()) {
463 /* as long as the point we're adding is not at zero,
464 * add an "anchor" point there.
468 _events.insert (_events.end(), new ControlEvent (0, _default_value));
469 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _default_value));
473 ControlEvent cp (when, 0.0f);
474 iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
475 DEBUG_TRACE (DEBUG::ControlList, string_compose ("editor_add: actually add when= %1 value= %2\n", when, value));
476 _events.insert (i, new ControlEvent (when, value));
480 maybe_signal_changed ();
485 ControlList::maybe_add_insert_guard (double when)
487 if (most_recent_insert_iterator != _events.end()) {
488 if ((*most_recent_insert_iterator)->when - when > 64) {
489 /* Next control point is some distance from where our new point is
490 going to go, so add a new point to avoid changing the shape of
491 the line too much. The insert iterator needs to point to the
492 new control point so that our insert will happen correctly. */
493 most_recent_insert_iterator = _events.insert (
494 most_recent_insert_iterator,
495 new ControlEvent (when + 1, (*most_recent_insert_iterator)->value));
496 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added insert guard point @ %2 = %3\n",
498 (*most_recent_insert_iterator)->value));
503 /** If we would just be adding to a straight line, move the previous point instead. */
505 ControlList::maybe_insert_straight_line (double when, double value)
507 if (_events.empty()) {
511 if (_events.back()->value == value) {
512 // Point b at the final point, which we know exists
513 EventList::iterator b = _events.end();
515 if (b == _events.begin()) {
516 return false; // No previous point
519 // Check the previous point's value
521 if ((*b)->value == value) {
522 /* At least two points with the exact same value (straight
523 line), just move the final point to the new time. */
524 _events.back()->when = when;
525 DEBUG_TRACE (DEBUG::ControlList, string_compose ("final value of %1 moved to %2\n", value, when));
532 ControlList::iterator
533 ControlList::erase_from_iterator_to (iterator iter, double when)
535 while (iter != _events.end()) {
536 if ((*iter)->when < when) {
537 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 erase existing @ %2\n", this, (*iter)->when));
539 iter = _events.erase (iter);
541 } else if ((*iter)->when >= when) {
550 ControlList::add (double when, double value, bool with_guards, bool with_default)
552 /* this is for making changes from some kind of user interface or
553 control surface (GUI, MIDI, OSC etc)
556 DEBUG_TRACE (DEBUG::ControlList,
557 string_compose ("@%1 add %2 at %3 guards = %4 write pass = %5 (new? %6) at end? %7\n",
558 this, value, when, with_guards, _in_write_pass, new_write_pass,
559 (most_recent_insert_iterator == _events.end())));
561 Glib::Threads::Mutex::Lock lm (_lock);
562 ControlEvent cp (when, 0.0f);
563 iterator insertion_point;
565 if (_events.empty() && with_default) {
567 /* empty: add an "anchor" point if the point we're adding past time 0 */
570 _events.insert (_events.end(), new ControlEvent (0, _default_value));
571 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _default_value));
575 if (_in_write_pass && new_write_pass) {
577 /* first write in a write pass: add guard point if requested */
580 add_guard_point (insert_position);
581 did_write_during_pass = true;
583 /* not adding a guard, but we need to set iterator appropriately */
584 const ControlEvent cp (when, 0.0);
585 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
587 new_write_pass = false;
589 } else if (_in_write_pass &&
590 (most_recent_insert_iterator == _events.end() || when > (*most_recent_insert_iterator)->when)) {
592 /* in write pass: erase from most recent insert to now */
594 if (most_recent_insert_iterator != _events.end()) {
595 /* advance to avoid deleting the last inserted point itself. */
596 ++most_recent_insert_iterator;
599 most_recent_insert_iterator = erase_from_iterator_to(most_recent_insert_iterator, when);
601 maybe_add_insert_guard (when);
604 } else if (!_in_write_pass) {
606 /* not in a write pass: figure out the iterator we should insert in front of */
608 DEBUG_TRACE (DEBUG::ControlList, string_compose ("compute(b) MRI for position %1\n", when));
609 ControlEvent cp (when, 0.0f);
610 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
613 /* OK, now we're really ready to add a new point */
615 if (most_recent_insert_iterator == _events.end()) {
616 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 appending new point at end\n", this));
618 const bool done = maybe_insert_straight_line (when, value);
620 _events.push_back (new ControlEvent (when, value));
621 DEBUG_TRACE (DEBUG::ControlList, string_compose ("\tactually appended, size now %1\n", _events.size()));
624 most_recent_insert_iterator = _events.end();
625 --most_recent_insert_iterator;
627 } else if ((*most_recent_insert_iterator)->when == when) {
629 if ((*most_recent_insert_iterator)->value != value) {
630 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 reset existing point to new value %2\n", this, value));
632 /* only one point allowed per time point, so just
633 * reset the value here.
636 (*most_recent_insert_iterator)->value = value;
638 /* if we modified the final value, then its as
639 * if we inserted a new point as far as the
640 * next addition, so make sure we know that.
643 if (_events.back()->when == when) {
644 most_recent_insert_iterator = _events.end();
648 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 same time %2, same value value %3\n", this, when, value));
652 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert new point at %2 at iterator at %3\n", this, when, (*most_recent_insert_iterator)->when));
654 const bool done = maybe_insert_straight_line (when, value);
656 maybe_add_insert_guard(when);
660 EventList::iterator x = _events.insert (most_recent_insert_iterator, new ControlEvent (when, value));
661 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 inserted new value before MRI, size now %2\n", this, _events.size()));
662 most_recent_insert_iterator = x;
669 maybe_signal_changed ();
673 ControlList::erase (iterator i)
676 Glib::Threads::Mutex::Lock lm (_lock);
677 if (most_recent_insert_iterator == i) {
678 unlocked_invalidate_insert_iterator ();
683 maybe_signal_changed ();
687 ControlList::erase (iterator start, iterator end)
690 Glib::Threads::Mutex::Lock lm (_lock);
691 _events.erase (start, end);
692 unlocked_invalidate_insert_iterator ();
695 maybe_signal_changed ();
698 /** Erase the first event which matches the given time and value */
700 ControlList::erase (double when, double value)
703 Glib::Threads::Mutex::Lock lm (_lock);
705 iterator i = begin ();
706 while (i != end() && ((*i)->when != when || (*i)->value != value)) {
712 if (most_recent_insert_iterator == i) {
713 unlocked_invalidate_insert_iterator ();
720 maybe_signal_changed ();
724 ControlList::erase_range (double start, double endt)
729 Glib::Threads::Mutex::Lock lm (_lock);
730 erased = erase_range_internal (start, endt, _events);
739 maybe_signal_changed ();
744 ControlList::erase_range_internal (double start, double endt, EventList & events)
747 ControlEvent cp (start, 0.0f);
751 if ((s = lower_bound (events.begin(), events.end(), &cp, time_comparator)) != events.end()) {
753 e = upper_bound (events.begin(), events.end(), &cp, time_comparator);
756 unlocked_invalidate_insert_iterator ();
765 ControlList::slide (iterator before, double distance)
768 Glib::Threads::Mutex::Lock lm (_lock);
770 if (before == _events.end()) {
774 while (before != _events.end()) {
775 (*before)->when += distance;
782 maybe_signal_changed ();
786 ControlList::shift (double pos, double frames)
789 Glib::Threads::Mutex::Lock lm (_lock);
791 for (iterator i = _events.begin(); i != _events.end(); ++i) {
792 if ((*i)->when >= pos) {
793 (*i)->when += frames;
800 maybe_signal_changed ();
804 ControlList::modify (iterator iter, double when, double val)
806 /* note: we assume higher level logic is in place to avoid this
807 reordering the time-order of control events in the list. ie. all
808 points after *iter are later than when.
812 Glib::Threads::Mutex::Lock lm (_lock);
814 (*iter)->when = when;
815 (*iter)->value = val;
816 if (isnan_local (val)) {
821 _events.sort (event_time_less_than);
822 unlocked_invalidate_insert_iterator ();
824 _sort_pending = true;
830 maybe_signal_changed ();
833 std::pair<ControlList::iterator,ControlList::iterator>
834 ControlList::control_points_adjacent (double xval)
836 Glib::Threads::Mutex::Lock lm (_lock);
838 ControlEvent cp (xval, 0.0f);
839 std::pair<iterator,iterator> ret;
841 ret.first = _events.end();
842 ret.second = _events.end();
844 for (i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator); i != _events.end(); ++i) {
846 if (ret.first == _events.end()) {
847 if ((*i)->when >= xval) {
848 if (i != _events.begin()) {
857 if ((*i)->when > xval) {
867 ControlList::freeze ()
882 Glib::Threads::Mutex::Lock lm (_lock);
885 _events.sort (event_time_less_than);
886 unlocked_invalidate_insert_iterator ();
887 _sort_pending = false;
893 ControlList::mark_dirty () const
895 _lookup_cache.left = -1;
896 _lookup_cache.range.first = _events.end();
897 _lookup_cache.range.second = _events.end();
898 _search_cache.left = -1;
899 _search_cache.first = _events.end();
902 _curve->mark_dirty();
905 Dirty (); /* EMIT SIGNAL */
909 ControlList::truncate_end (double last_coordinate)
912 Glib::Threads::Mutex::Lock lm (_lock);
913 ControlEvent cp (last_coordinate, 0);
914 ControlList::reverse_iterator i;
917 if (_events.empty()) {
921 if (last_coordinate == _events.back()->when) {
925 if (last_coordinate > _events.back()->when) {
930 iterator foo = _events.begin();
933 if (foo == _events.end()) {
935 } else if (++foo == _events.end()) {
942 /* less than 2 points: add a new point */
943 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
946 /* more than 2 points: check to see if the last 2 values
947 are equal. if so, just move the position of the
948 last point. otherwise, add a new point.
951 iterator penultimate = _events.end();
952 --penultimate; /* points at last point */
953 --penultimate; /* points at the penultimate point */
955 if (_events.back()->value == (*penultimate)->value) {
956 _events.back()->when = last_coordinate;
958 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
966 last_val = unlocked_eval (last_coordinate);
967 last_val = max ((double) _min_yval, last_val);
968 last_val = min ((double) _max_yval, last_val);
970 i = _events.rbegin();
972 /* make i point to the last control point */
976 /* now go backwards, removing control points that are
977 beyond the new last coordinate.
980 // FIXME: SLOW! (size() == O(n))
982 uint32_t sz = _events.size();
984 while (i != _events.rend() && sz > 2) {
985 ControlList::reverse_iterator tmp;
990 if ((*i)->when < last_coordinate) {
994 _events.erase (i.base());
1000 _events.back()->when = last_coordinate;
1001 _events.back()->value = last_val;
1004 unlocked_invalidate_insert_iterator ();
1008 maybe_signal_changed ();
1012 ControlList::truncate_start (double overall_length)
1015 Glib::Threads::Mutex::Lock lm (_lock);
1017 double first_legal_value;
1018 double first_legal_coordinate;
1020 assert(!_events.empty());
1022 if (overall_length == _events.back()->when) {
1023 /* no change in overall length */
1027 if (overall_length > _events.back()->when) {
1029 /* growing at front: duplicate first point. shift all others */
1031 double shift = overall_length - _events.back()->when;
1034 for (np = 0, i = _events.begin(); i != _events.end(); ++i, ++np) {
1035 (*i)->when += shift;
1040 /* less than 2 points: add a new point */
1041 _events.push_front (new ControlEvent (0, _events.front()->value));
1045 /* more than 2 points: check to see if the first 2 values
1046 are equal. if so, just move the position of the
1047 first point. otherwise, add a new point.
1050 iterator second = _events.begin();
1051 ++second; /* points at the second point */
1053 if (_events.front()->value == (*second)->value) {
1054 /* first segment is flat, just move start point back to zero */
1055 _events.front()->when = 0;
1057 /* leave non-flat segment in place, add a new leading point. */
1058 _events.push_front (new ControlEvent (0, _events.front()->value));
1064 /* shrinking at front */
1066 first_legal_coordinate = _events.back()->when - overall_length;
1067 first_legal_value = unlocked_eval (first_legal_coordinate);
1068 first_legal_value = max (_min_yval, first_legal_value);
1069 first_legal_value = min (_max_yval, first_legal_value);
1071 /* remove all events earlier than the new "front" */
1073 i = _events.begin();
1075 while (i != _events.end() && !_events.empty()) {
1076 ControlList::iterator tmp;
1081 if ((*i)->when > first_legal_coordinate) {
1091 /* shift all remaining points left to keep their same
1095 for (i = _events.begin(); i != _events.end(); ++i) {
1096 (*i)->when -= first_legal_coordinate;
1099 /* add a new point for the interpolated new value */
1101 _events.push_front (new ControlEvent (0, first_legal_value));
1104 unlocked_invalidate_insert_iterator ();
1108 maybe_signal_changed ();
1112 ControlList::unlocked_eval (double x) const
1114 pair<EventList::iterator,EventList::iterator> range;
1120 const_iterator length_check_iter = _events.begin();
1121 for (npoints = 0; npoints < 4; ++npoints, ++length_check_iter) {
1122 if (length_check_iter == _events.end()) {
1129 return _default_value;
1132 return _events.front()->value;
1135 if (x >= _events.back()->when) {
1136 return _events.back()->value;
1137 } else if (x <= _events.front()->when) {
1138 return _events.front()->value;
1141 lpos = _events.front()->when;
1142 lval = _events.front()->value;
1143 upos = _events.back()->when;
1144 uval = _events.back()->value;
1146 if (_interpolation == Discrete) {
1150 /* linear interpolation betweeen the two points */
1151 fraction = (double) (x - lpos) / (double) (upos - lpos);
1152 return lval + (fraction * (uval - lval));
1155 if (x >= _events.back()->when) {
1156 return _events.back()->value;
1157 } else if (x <= _events.front()->when) {
1158 return _events.front()->value;
1161 return multipoint_eval (x);
1164 abort(); /*NOTREACHED*/ /* stupid gcc */
1165 return _default_value;
1169 ControlList::multipoint_eval (double x) const
1175 /* "Stepped" lookup (no interpolation) */
1176 /* FIXME: no cache. significant? */
1177 if (_interpolation == Discrete) {
1178 const ControlEvent cp (x, 0);
1179 EventList::const_iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
1181 // shouldn't have made it to multipoint_eval
1182 assert(i != _events.end());
1184 if (i == _events.begin() || (*i)->when == x)
1187 return (*(--i))->value;
1190 /* Only do the range lookup if x is in a different range than last time
1191 * this was called (or if the lookup cache has been marked "dirty" (left<0) */
1192 if ((_lookup_cache.left < 0) ||
1193 ((_lookup_cache.left > x) ||
1194 (_lookup_cache.range.first == _events.end()) ||
1195 ((*_lookup_cache.range.second)->when < x))) {
1197 const ControlEvent cp (x, 0);
1199 _lookup_cache.range = equal_range (_events.begin(), _events.end(), &cp, time_comparator);
1202 pair<const_iterator,const_iterator> range = _lookup_cache.range;
1204 if (range.first == range.second) {
1206 /* x does not exist within the list as a control point */
1208 _lookup_cache.left = x;
1210 if (range.first != _events.begin()) {
1212 lpos = (*range.first)->when;
1213 lval = (*range.first)->value;
1215 /* we're before the first point */
1216 // return _default_value;
1217 return _events.front()->value;
1220 if (range.second == _events.end()) {
1221 /* we're after the last point */
1222 return _events.back()->value;
1225 upos = (*range.second)->when;
1226 uval = (*range.second)->value;
1228 /* linear interpolation betweeen the two points
1232 fraction = (double) (x - lpos) / (double) (upos - lpos);
1233 return lval + (fraction * (uval - lval));
1237 /* x is a control point in the data */
1238 _lookup_cache.left = -1;
1239 return (*range.first)->value;
1243 ControlList::build_search_cache_if_necessary (double start) const
1245 if (_events.empty()) {
1246 /* Empty, nothing to cache, move to end. */
1247 _search_cache.first = _events.end();
1248 _search_cache.left = 0;
1250 } else if ((_search_cache.left < 0) || (_search_cache.left > start)) {
1251 /* Marked dirty (left < 0), or we're too far forward, re-search. */
1253 const ControlEvent start_point (start, 0);
1255 _search_cache.first = lower_bound (_events.begin(), _events.end(), &start_point, time_comparator);
1256 _search_cache.left = start;
1259 /* We now have a search cache that is not too far right, but it may be too
1260 far left and need to be advanced. */
1262 while (_search_cache.first != end() && (*_search_cache.first)->when < start) {
1263 ++_search_cache.first;
1265 _search_cache.left = start;
1268 /** Get the earliest event after \a start using the current interpolation style.
1270 * If an event is found, \a x and \a y are set to its coordinates.
1272 * \param inclusive Include events with timestamp exactly equal to \a start
1273 * \return true if event is found (and \a x and \a y are valid).
1276 ControlList::rt_safe_earliest_event (double start, double& x, double& y, bool inclusive) const
1278 // FIXME: It would be nice if this was unnecessary..
1279 Glib::Threads::Mutex::Lock lm(_lock, Glib::Threads::TRY_LOCK);
1284 return rt_safe_earliest_event_unlocked (start, x, y, inclusive);
1288 /** Get the earliest event after \a start using the current interpolation style.
1290 * If an event is found, \a x and \a y are set to its coordinates.
1292 * \param inclusive Include events with timestamp exactly equal to \a start
1293 * \return true if event is found (and \a x and \a y are valid).
1296 ControlList::rt_safe_earliest_event_unlocked (double start, double& x, double& y, bool inclusive) const
1298 if (_interpolation == Discrete) {
1299 return rt_safe_earliest_event_discrete_unlocked(start, x, y, inclusive);
1301 return rt_safe_earliest_event_linear_unlocked(start, x, y, inclusive);
1306 /** Get the earliest event after \a start without interpolation.
1308 * If an event is found, \a x and \a y are set to its coordinates.
1310 * \param inclusive Include events with timestamp exactly equal to \a start
1311 * \return true if event is found (and \a x and \a y are valid).
1314 ControlList::rt_safe_earliest_event_discrete_unlocked (double start, double& x, double& y, bool inclusive) const
1316 build_search_cache_if_necessary (start);
1318 if (_search_cache.first != _events.end()) {
1319 const ControlEvent* const first = *_search_cache.first;
1321 const bool past_start = (inclusive ? first->when >= start : first->when > start);
1323 /* Earliest points is in range, return it */
1329 /* Move left of cache to this point
1330 * (Optimize for immediate call this cycle within range) */
1331 _search_cache.left = x;
1332 ++_search_cache.first;
1341 /* No points in range */
1347 /** Get the earliest time the line crosses an integer (Linear interpolation).
1349 * If an event is found, \a x and \a y are set to its coordinates.
1351 * \param inclusive Include events with timestamp exactly equal to \a start
1352 * \return true if event is found (and \a x and \a y are valid).
1355 ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, double& y, bool inclusive) const
1357 // cout << "earliest_event(start: " << start << ", x: " << x << ", y: " << y << ", inclusive: " << inclusive << ")" << endl;
1359 const_iterator length_check_iter = _events.begin();
1360 if (_events.empty()) { // 0 events
1362 } else if (_events.end() == ++length_check_iter) { // 1 event
1363 return rt_safe_earliest_event_discrete_unlocked (start, x, y, inclusive);
1366 // Hack to avoid infinitely repeating the same event
1367 build_search_cache_if_necessary (start);
1369 if (_search_cache.first != _events.end()) {
1371 const ControlEvent* first = NULL;
1372 const ControlEvent* next = NULL;
1374 if (_search_cache.first == _events.begin() || (*_search_cache.first)->when <= start) {
1375 /* Step is after first */
1376 first = *_search_cache.first;
1377 ++_search_cache.first;
1378 if (_search_cache.first == _events.end()) {
1381 next = *_search_cache.first;
1384 /* Step is before first */
1385 const_iterator prev = _search_cache.first;
1388 next = *_search_cache.first;
1391 if (inclusive && first->when == start) {
1394 /* Move left of cache to this point
1395 * (Optimize for immediate call this cycle within range) */
1396 _search_cache.left = x;
1398 } else if (next->when < start || (!inclusive && next->when == start)) {
1399 /* "Next" is before the start, no points left. */
1403 if (fabs(first->value - next->value) <= 1) {
1404 if (next->when > start) {
1407 /* Move left of cache to this point
1408 * (Optimize for immediate call this cycle within range) */
1409 _search_cache.left = x;
1416 const double slope = (next->value - first->value) / (double)(next->when - first->when);
1417 //cerr << "start y: " << start_y << endl;
1419 //y = first->value + (slope * fabs(start - first->when));
1422 if (first->value < next->value) // ramping up
1424 else // ramping down
1427 x = first->when + (y - first->value) / (double)slope;
1429 while ((inclusive && x < start) || (x <= start && y != next->value)) {
1431 if (first->value < next->value) // ramping up
1433 else // ramping down
1436 x = first->when + (y - first->value) / (double)slope;
1439 /*cerr << first->value << " @ " << first->when << " ... "
1440 << next->value << " @ " << next->when
1441 << " = " << y << " @ " << x << endl;*/
1443 assert( (y >= first->value && y <= next->value)
1444 || (y <= first->value && y >= next->value) );
1447 const bool past_start = (inclusive ? x >= start : x > start);
1449 /* Move left of cache to this point
1450 * (Optimize for immediate call this cycle within range) */
1451 _search_cache.left = x;
1452 assert(inclusive ? x >= start : x > start);
1460 _search_cache.left = x;
1465 /* No points in the future, so no steps (towards them) in the future */
1471 /** @param start Start position in model coordinates.
1472 * @param end End position in model coordinates.
1473 * @param op 0 = cut, 1 = copy, 2 = clear.
1475 boost::shared_ptr<ControlList>
1476 ControlList::cut_copy_clear (double start, double end, int op)
1478 boost::shared_ptr<ControlList> nal = create (_parameter, _desc);
1480 ControlEvent cp (start, 0.0);
1483 Glib::Threads::Mutex::Lock lm (_lock);
1485 /* first, determine s & e, two iterators that define the range of points
1486 affected by this operation
1489 if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) == _events.end()) {
1493 /* and the last that is at or after `end' */
1495 e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1498 /* if "start" isn't the location of an existing point,
1499 evaluate the curve to get a value for the start. Add a point to
1500 both the existing event list, and if its not a "clear" operation,
1501 to the copy ("nal") as well.
1503 Note that the time positions of the points in each list are different
1504 because we want the copy ("nal") to have a zero time reference.
1508 /* before we begin any cut/clear operations, get the value of the curve
1512 double end_value = unlocked_eval (end);
1514 if ((*s)->when != start) {
1516 double val = unlocked_eval (start);
1518 if (op == 0) { // cut
1519 if (start > _events.front()->when) {
1520 _events.insert (s, (new ControlEvent (start, val)));
1524 if (op != 2) { // ! clear
1525 nal->_events.push_back (new ControlEvent (0, val));
1529 for (iterator x = s; x != e; ) {
1531 /* adjust new points to be relative to start, which
1532 has been set to zero.
1536 nal->_events.push_back (new ControlEvent ((*x)->when - start, (*x)->value));
1540 x = _events.erase (x);
1546 if (e == _events.end() || (*e)->when != end) {
1548 /* only add a boundary point if there is a point after "end"
1551 if (op == 0 && (e != _events.end() && end < (*e)->when)) { // cut
1552 _events.insert (e, new ControlEvent (end, end_value));
1555 if (op != 2 && (e != _events.end() && end < (*e)->when)) { // cut/copy
1556 nal->_events.push_back (new ControlEvent (end - start, end_value));
1560 unlocked_invalidate_insert_iterator ();
1565 maybe_signal_changed ();
1572 boost::shared_ptr<ControlList>
1573 ControlList::cut (double start, double end)
1575 return cut_copy_clear (start, end, 0);
1578 boost::shared_ptr<ControlList>
1579 ControlList::copy (double start, double end)
1581 return cut_copy_clear (start, end, 1);
1585 ControlList::clear (double start, double end)
1587 cut_copy_clear (start, end, 2);
1590 /** @param pos Position in model coordinates */
1592 ControlList::paste (const ControlList& alist, double pos, float /*times*/)
1594 if (alist._events.empty()) {
1599 Glib::Threads::Mutex::Lock lm (_lock);
1603 ControlEvent cp (pos, 0.0);
1605 where = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1607 for (const_iterator i = alist.begin();i != alist.end(); ++i) {
1608 double value = (*i)->value;
1609 if (alist.parameter() != parameter()) {
1610 const ParameterDescriptor& src_desc = alist.descriptor();
1612 value -= src_desc.lower; // translate to 0-relative
1613 value /= (src_desc.upper - src_desc.lower); // normalize range
1614 value *= (_desc.upper - _desc.lower); // scale to our range
1615 value += _desc.lower; // translate to our offset
1617 _events.insert (where, new ControlEvent((*i)->when + pos, value));
1618 end = (*i)->when + pos;
1622 /* move all points after the insertion along the timeline by
1626 while (where != _events.end()) {
1628 if ((*where)->when <= end) {
1631 _events.erase(where);
1639 unlocked_invalidate_insert_iterator ();
1643 maybe_signal_changed ();
1647 /** Move automation around according to a list of region movements.
1648 * @param return true if anything was changed, otherwise false (ie nothing needed changing)
1651 ControlList::move_ranges (const list< RangeMove<double> >& movements)
1653 typedef list< RangeMove<double> > RangeMoveList;
1656 Glib::Threads::Mutex::Lock lm (_lock);
1658 /* a copy of the events list before we started moving stuff around */
1659 EventList old_events = _events;
1661 /* clear the source and destination ranges in the new list */
1662 bool things_erased = false;
1663 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1665 if (erase_range_internal (i->from, i->from + i->length, _events)) {
1666 things_erased = true;
1669 if (erase_range_internal (i->to, i->to + i->length, _events)) {
1670 things_erased = true;
1674 /* if nothing was erased, there is nothing to do */
1675 if (!things_erased) {
1679 /* copy the events into the new list */
1680 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1681 iterator j = old_events.begin ();
1682 const double limit = i->from + i->length;
1683 const double dx = i->to - i->from;
1684 while (j != old_events.end () && (*j)->when <= limit) {
1685 if ((*j)->when >= i->from) {
1686 ControlEvent* ev = new ControlEvent (**j);
1688 _events.push_back (ev);
1695 _events.sort (event_time_less_than);
1696 unlocked_invalidate_insert_iterator ();
1698 _sort_pending = true;
1704 maybe_signal_changed ();
1709 ControlList::set_interpolation (InterpolationStyle s)
1711 if (_interpolation == s) {
1716 InterpolationChanged (s); /* EMIT SIGNAL */
1720 ControlList::operator!= (ControlList const & other) const
1722 if (_events.size() != other._events.size()) {
1726 EventList::const_iterator i = _events.begin ();
1727 EventList::const_iterator j = other._events.begin ();
1729 while (i != _events.end() && (*i)->when == (*j)->when && (*i)->value == (*j)->value) {
1734 if (i != _events.end ()) {
1739 _parameter != other._parameter ||
1740 _interpolation != other._interpolation ||
1741 _min_yval != other._min_yval ||
1742 _max_yval != other._max_yval ||
1743 _default_value != other._default_value
1748 ControlList::dump (ostream& o)
1750 /* NOT LOCKED ... for debugging only */
1752 for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
1753 o << (*x)->value << " @ " << (uint64_t) (*x)->when << endl;
1757 } // namespace Evoral