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"
39 #include "evoral/types.hpp"
41 #include "pbd/compose.h"
42 #include "pbd/debug.h"
49 inline bool event_time_less_than (ControlEvent* a, ControlEvent* b)
51 return a->when < b->when;
54 ControlList::ControlList (const Parameter& id, const ParameterDescriptor& desc)
59 _interpolation = desc.toggled ? Discrete : Linear;
61 _changed_when_thawed = false;
62 _min_yval = desc.lower;
63 _max_yval = desc.upper;
64 _default_value = desc.normal;
65 _lookup_cache.left = -1;
66 _lookup_cache.range.first = _events.end();
67 _lookup_cache.range.second = _events.end();
68 _search_cache.left = -1;
69 _search_cache.first = _events.end();
70 _sort_pending = false;
71 new_write_pass = true;
72 _in_write_pass = false;
73 did_write_during_pass = false;
75 most_recent_insert_iterator = _events.end();
78 ControlList::ControlList (const ControlList& other)
79 : _parameter(other._parameter)
81 , _interpolation(other._interpolation)
85 _changed_when_thawed = false;
86 _min_yval = other._min_yval;
87 _max_yval = other._max_yval;
88 _default_value = other._default_value;
89 _lookup_cache.range.first = _events.end();
90 _lookup_cache.range.second = _events.end();
91 _search_cache.first = _events.end();
92 _sort_pending = false;
93 new_write_pass = true;
94 _in_write_pass = false;
95 did_write_during_pass = false;
97 most_recent_insert_iterator = _events.end();
104 ControlList::ControlList (const ControlList& other, double start, double end)
105 : _parameter(other._parameter)
107 , _interpolation(other._interpolation)
111 _changed_when_thawed = false;
112 _min_yval = other._min_yval;
113 _max_yval = other._max_yval;
114 _default_value = other._default_value;
115 _lookup_cache.range.first = _events.end();
116 _lookup_cache.range.second = _events.end();
117 _search_cache.first = _events.end();
118 _sort_pending = false;
120 /* now grab the relevant points, and shift them back if necessary */
122 boost::shared_ptr<ControlList> section = const_cast<ControlList*>(&other)->copy (start, end);
124 if (!section->empty()) {
125 copy_events (*(section.get()));
128 new_write_pass = false;
129 _in_write_pass = false;
130 did_write_during_pass = false;
131 insert_position = -1;
132 most_recent_insert_iterator = _events.end();
137 ControlList::~ControlList()
139 for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
146 boost::shared_ptr<ControlList>
147 ControlList::create(const Parameter& id, const ParameterDescriptor& desc)
149 return boost::shared_ptr<ControlList>(new ControlList(id, desc));
153 ControlList::operator== (const ControlList& other)
155 return _events == other._events;
159 ControlList::operator= (const ControlList& other)
161 if (this != &other) {
163 _min_yval = other._min_yval;
164 _max_yval = other._max_yval;
167 _interpolation = other._interpolation;
168 _default_value = other._default_value;
177 ControlList::copy_events (const ControlList& other)
180 Glib::Threads::RWLock::WriterLock lm (_lock);
182 for (const_iterator i = other.begin(); i != other.end(); ++i) {
183 _events.push_back (new ControlEvent ((*i)->when, (*i)->value));
185 unlocked_invalidate_insert_iterator ();
188 maybe_signal_changed ();
192 ControlList::create_curve()
194 _curve = new Curve(*this);
198 ControlList::destroy_curve()
205 ControlList::maybe_signal_changed ()
210 _changed_when_thawed = true;
215 ControlList::clear ()
218 Glib::Threads::RWLock::WriterLock lm (_lock);
220 unlocked_invalidate_insert_iterator ();
224 maybe_signal_changed ();
228 ControlList::x_scale (double factor)
230 Glib::Threads::RWLock::WriterLock lm (_lock);
235 ControlList::extend_to (double when)
237 Glib::Threads::RWLock::WriterLock lm (_lock);
238 if (_events.empty() || _events.back()->when == when) {
241 double factor = when / _events.back()->when;
247 ControlList::_x_scale (double factor)
249 for (iterator i = _events.begin(); i != _events.end(); ++i) {
250 (*i)->when *= factor;
256 struct ControlEventTimeComparator {
257 bool operator() (ControlEvent* a, ControlEvent* b) {
258 return a->when < b->when;
263 ControlList::thin (double thinning_factor)
265 if (thinning_factor == 0.0 || _desc.toggled) {
269 bool changed = false;
272 Glib::Threads::RWLock::WriterLock lm (_lock);
274 ControlEvent* prevprev = 0;
275 ControlEvent* cur = 0;
276 ControlEvent* prev = 0;
280 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 thin from %2 events\n", this, _events.size()));
282 for (iterator i = _events.begin(); i != _events.end(); ++i) {
289 /* compute the area of the triangle formed by 3 points
292 double area = fabs ((prevprev->when * (prev->value - cur->value)) +
293 (prev->when * (cur->value - prevprev->value)) +
294 (cur->when * (prevprev->value - prev->value)));
296 if (area < thinning_factor) {
297 iterator tmp = pprev;
299 /* pprev will change to current
300 i is incremented to the next event
316 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 thin => %2 events\n", this, _events.size()));
319 unlocked_invalidate_insert_iterator ();
325 maybe_signal_changed ();
330 ControlList::fast_simple_add (double when, double value)
332 Glib::Threads::RWLock::WriterLock lm (_lock);
333 /* to be used only for loading pre-sorted data from saved state */
334 _events.insert (_events.end(), new ControlEvent (when, value));
340 ControlList::invalidate_insert_iterator ()
342 Glib::Threads::RWLock::WriterLock 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::RWLock::WriterLock 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, bool with_guard)
458 /* this is for making changes from a graphical line editor
461 ControlEvent cp (when, 0.0f);
462 iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
464 if (i != _events.end () && (*i)->when == when) {
468 if (_events.empty()) {
470 /* as long as the point we're adding is not at zero,
471 * add an "anchor" point there.
475 _events.insert (_events.end(), new ControlEvent (0, value));
476 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added value %2 at zero\n", this, value));
480 insert_position = when;
483 add_guard_point (when - 64);
485 maybe_add_insert_guard (when);
489 DEBUG_TRACE (DEBUG::ControlList, string_compose ("editor_add: actually add when= %1 value= %2\n", when, value));
490 result = _events.insert (i, new ControlEvent (when, value));
497 maybe_signal_changed ();
503 ControlList::maybe_add_insert_guard (double when)
505 if (most_recent_insert_iterator != _events.end()) {
506 if ((*most_recent_insert_iterator)->when - when > 64) {
507 /* Next control point is some distance from where our new point is
508 going to go, so add a new point to avoid changing the shape of
509 the line too much. The insert iterator needs to point to the
510 new control point so that our insert will happen correctly. */
511 most_recent_insert_iterator = _events.insert (
512 most_recent_insert_iterator,
513 new ControlEvent (when + 64, (*most_recent_insert_iterator)->value));
514 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added insert guard point @ %2 = %3\n",
516 (*most_recent_insert_iterator)->value));
521 /** If we would just be adding to a straight line, move the previous point instead. */
523 ControlList::maybe_insert_straight_line (double when, double value)
525 if (_events.empty()) {
529 if (_events.back()->value == value) {
530 // Point b at the final point, which we know exists
531 EventList::iterator b = _events.end();
533 if (b == _events.begin()) {
534 return false; // No previous point
537 // Check the previous point's value
539 if ((*b)->value == value) {
540 /* At least two points with the exact same value (straight
541 line), just move the final point to the new time. */
542 _events.back()->when = when;
543 DEBUG_TRACE (DEBUG::ControlList, string_compose ("final value of %1 moved to %2\n", value, when));
550 ControlList::iterator
551 ControlList::erase_from_iterator_to (iterator iter, double when)
553 while (iter != _events.end()) {
554 if ((*iter)->when < when) {
555 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 erase existing @ %2\n", this, (*iter)->when));
557 iter = _events.erase (iter);
559 } else if ((*iter)->when >= when) {
568 ControlList::add (double when, double value, bool with_guards, bool with_initial)
570 /* this is for making changes from some kind of user interface or
571 control surface (GUI, MIDI, OSC etc)
574 DEBUG_TRACE (DEBUG::ControlList,
575 string_compose ("@%1 add %2 at %3 guards = %4 write pass = %5 (new? %6) at end? %7\n",
576 this, value, when, with_guards, _in_write_pass, new_write_pass,
577 (most_recent_insert_iterator == _events.end())));
579 Glib::Threads::RWLock::WriterLock lm (_lock);
580 ControlEvent cp (when, 0.0f);
581 iterator insertion_point;
583 if (_events.empty() && with_initial) {
585 /* empty: add an "anchor" point if the point we're adding past time 0 */
589 const double opp_val = ((value < 0.5) ? 1.0 : 0.0);
590 _events.insert (_events.end(), new ControlEvent (0, opp_val));
591 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added toggled value %2 at zero\n", this, opp_val));
594 _events.insert (_events.end(), new ControlEvent (0, value));
595 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _default_value));
600 if (_in_write_pass && new_write_pass) {
602 /* first write in a write pass: add guard point if requested */
605 add_guard_point (insert_position);
606 did_write_during_pass = true;
608 /* not adding a guard, but we need to set iterator appropriately */
609 const ControlEvent cp (when, 0.0);
610 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
612 new_write_pass = false;
614 } else if (_in_write_pass &&
615 (most_recent_insert_iterator == _events.end() || when > (*most_recent_insert_iterator)->when)) {
617 /* in write pass: erase from most recent insert to now */
619 if (most_recent_insert_iterator != _events.end()) {
620 /* advance to avoid deleting the last inserted point itself. */
621 ++most_recent_insert_iterator;
624 most_recent_insert_iterator = erase_from_iterator_to(most_recent_insert_iterator, when);
626 maybe_add_insert_guard (when);
629 } else if (!_in_write_pass) {
631 /* not in a write pass: figure out the iterator we should insert in front of */
633 DEBUG_TRACE (DEBUG::ControlList, string_compose ("compute(b) MRI for position %1\n", when));
634 ControlEvent cp (when, 0.0f);
635 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
638 /* OK, now we're really ready to add a new point */
640 if (most_recent_insert_iterator == _events.end()) {
641 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 appending new point at end\n", this));
643 const bool done = maybe_insert_straight_line (when, value);
645 _events.push_back (new ControlEvent (when, value));
646 DEBUG_TRACE (DEBUG::ControlList, string_compose ("\tactually appended, size now %1\n", _events.size()));
649 most_recent_insert_iterator = _events.end();
650 --most_recent_insert_iterator;
652 } else if ((*most_recent_insert_iterator)->when == when) {
654 if ((*most_recent_insert_iterator)->value != value) {
655 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 reset existing point to new value %2\n", this, value));
657 /* only one point allowed per time point, so add a guard point
658 * before it if needed then reset the value of the point.
661 (*most_recent_insert_iterator)->value = value;
663 /* if we modified the final value, then its as
664 * if we inserted a new point as far as the
665 * next addition, so make sure we know that.
668 if (_events.back()->when == when) {
669 most_recent_insert_iterator = _events.end();
673 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 same time %2, same value value %3\n", this, when, value));
677 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert new point at %2 at iterator at %3\n", this, when, (*most_recent_insert_iterator)->when));
679 /* check for possible straight line here until maybe_insert_straight_line () handles the insert iterator properly*/
680 if (most_recent_insert_iterator != _events.begin ()) {
681 bool have_point2 = false;
682 --most_recent_insert_iterator;
683 const bool have_point1 = (*most_recent_insert_iterator)->value == value;
685 if (most_recent_insert_iterator != _events.begin ()) {
686 --most_recent_insert_iterator;
687 have_point2 = (*most_recent_insert_iterator)->value == value;
688 ++most_recent_insert_iterator;
691 if (have_point1 && have_point2) {
692 (*most_recent_insert_iterator)->when = when;
695 ++most_recent_insert_iterator;
698 //done = maybe_insert_straight_line (when, value) || done;
699 /* if the transport is stopped, add guard points (?) */
700 if (!done && !_in_write_pass && when > 64) {
701 add_guard_point (when - 64);
702 maybe_add_insert_guard (when);
706 maybe_add_insert_guard (when);
710 EventList::iterator x = _events.insert (most_recent_insert_iterator, new ControlEvent (when, value));
711 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 inserted new value before MRI, size now %2\n", this, _events.size()));
712 most_recent_insert_iterator = x;
719 maybe_signal_changed ();
723 ControlList::erase (iterator i)
726 Glib::Threads::RWLock::WriterLock lm (_lock);
727 if (most_recent_insert_iterator == i) {
728 unlocked_invalidate_insert_iterator ();
733 maybe_signal_changed ();
737 ControlList::erase (iterator start, iterator end)
740 Glib::Threads::RWLock::WriterLock lm (_lock);
741 _events.erase (start, end);
742 unlocked_invalidate_insert_iterator ();
745 maybe_signal_changed ();
748 /** Erase the first event which matches the given time and value */
750 ControlList::erase (double when, double value)
753 Glib::Threads::RWLock::WriterLock lm (_lock);
755 iterator i = begin ();
756 while (i != end() && ((*i)->when != when || (*i)->value != value)) {
762 if (most_recent_insert_iterator == i) {
763 unlocked_invalidate_insert_iterator ();
770 maybe_signal_changed ();
774 ControlList::erase_range (double start, double endt)
779 Glib::Threads::RWLock::WriterLock lm (_lock);
780 erased = erase_range_internal (start, endt, _events);
789 maybe_signal_changed ();
794 ControlList::erase_range_internal (double start, double endt, EventList & events)
797 ControlEvent cp (start, 0.0f);
801 if ((s = lower_bound (events.begin(), events.end(), &cp, time_comparator)) != events.end()) {
803 e = upper_bound (events.begin(), events.end(), &cp, time_comparator);
806 unlocked_invalidate_insert_iterator ();
815 ControlList::slide (iterator before, double distance)
818 Glib::Threads::RWLock::WriterLock lm (_lock);
820 if (before == _events.end()) {
824 while (before != _events.end()) {
825 (*before)->when += distance;
832 maybe_signal_changed ();
836 ControlList::shift (double pos, double frames)
839 Glib::Threads::RWLock::WriterLock lm (_lock);
841 for (iterator i = _events.begin(); i != _events.end(); ++i) {
842 if ((*i)->when >= pos) {
843 (*i)->when += frames;
850 maybe_signal_changed ();
854 ControlList::modify (iterator iter, double when, double val)
856 /* note: we assume higher level logic is in place to avoid this
857 reordering the time-order of control events in the list. ie. all
858 points after *iter are later than when.
862 Glib::Threads::RWLock::WriterLock lm (_lock);
864 (*iter)->when = when;
865 (*iter)->value = val;
866 if (isnan_local (val)) {
871 _events.sort (event_time_less_than);
872 unlocked_invalidate_insert_iterator ();
874 _sort_pending = true;
880 maybe_signal_changed ();
883 std::pair<ControlList::iterator,ControlList::iterator>
884 ControlList::control_points_adjacent (double xval)
886 Glib::Threads::RWLock::ReaderLock lm (_lock);
888 ControlEvent cp (xval, 0.0f);
889 std::pair<iterator,iterator> ret;
891 ret.first = _events.end();
892 ret.second = _events.end();
894 for (i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator); i != _events.end(); ++i) {
896 if (ret.first == _events.end()) {
897 if ((*i)->when >= xval) {
898 if (i != _events.begin()) {
907 if ((*i)->when > xval) {
917 ControlList::freeze ()
932 Glib::Threads::RWLock::WriterLock lm (_lock);
935 _events.sort (event_time_less_than);
936 unlocked_invalidate_insert_iterator ();
937 _sort_pending = false;
943 ControlList::mark_dirty () const
945 _lookup_cache.left = -1;
946 _lookup_cache.range.first = _events.end();
947 _lookup_cache.range.second = _events.end();
948 _search_cache.left = -1;
949 _search_cache.first = _events.end();
952 _curve->mark_dirty();
955 Dirty (); /* EMIT SIGNAL */
959 ControlList::truncate_end (double last_coordinate)
962 Glib::Threads::RWLock::WriterLock lm (_lock);
963 ControlEvent cp (last_coordinate, 0);
964 ControlList::reverse_iterator i;
967 if (_events.empty()) {
971 if (last_coordinate == _events.back()->when) {
975 if (last_coordinate > _events.back()->when) {
980 iterator foo = _events.begin();
983 if (foo == _events.end()) {
985 } else if (++foo == _events.end()) {
992 /* less than 2 points: add a new point */
993 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
996 /* more than 2 points: check to see if the last 2 values
997 are equal. if so, just move the position of the
998 last point. otherwise, add a new point.
1001 iterator penultimate = _events.end();
1002 --penultimate; /* points at last point */
1003 --penultimate; /* points at the penultimate point */
1005 if (_events.back()->value == (*penultimate)->value) {
1006 _events.back()->when = last_coordinate;
1008 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
1014 /* shortening end */
1016 last_val = unlocked_eval (last_coordinate);
1017 last_val = max ((double) _min_yval, last_val);
1018 last_val = min ((double) _max_yval, last_val);
1020 i = _events.rbegin();
1022 /* make i point to the last control point */
1026 /* now go backwards, removing control points that are
1027 beyond the new last coordinate.
1030 // FIXME: SLOW! (size() == O(n))
1032 uint32_t sz = _events.size();
1034 while (i != _events.rend() && sz > 2) {
1035 ControlList::reverse_iterator tmp;
1040 if ((*i)->when < last_coordinate) {
1044 _events.erase (i.base());
1050 _events.back()->when = last_coordinate;
1051 _events.back()->value = last_val;
1054 unlocked_invalidate_insert_iterator ();
1058 maybe_signal_changed ();
1062 ControlList::truncate_start (double overall_length)
1065 Glib::Threads::RWLock::WriterLock lm (_lock);
1067 double first_legal_value;
1068 double first_legal_coordinate;
1070 if (_events.empty()) {
1071 /* nothing to truncate */
1073 } else if (overall_length == _events.back()->when) {
1074 /* no change in overall length */
1078 if (overall_length > _events.back()->when) {
1080 /* growing at front: duplicate first point. shift all others */
1082 double shift = overall_length - _events.back()->when;
1085 for (np = 0, i = _events.begin(); i != _events.end(); ++i, ++np) {
1086 (*i)->when += shift;
1091 /* less than 2 points: add a new point */
1092 _events.push_front (new ControlEvent (0, _events.front()->value));
1096 /* more than 2 points: check to see if the first 2 values
1097 are equal. if so, just move the position of the
1098 first point. otherwise, add a new point.
1101 iterator second = _events.begin();
1102 ++second; /* points at the second point */
1104 if (_events.front()->value == (*second)->value) {
1105 /* first segment is flat, just move start point back to zero */
1106 _events.front()->when = 0;
1108 /* leave non-flat segment in place, add a new leading point. */
1109 _events.push_front (new ControlEvent (0, _events.front()->value));
1115 /* shrinking at front */
1117 first_legal_coordinate = _events.back()->when - overall_length;
1118 first_legal_value = unlocked_eval (first_legal_coordinate);
1119 first_legal_value = max (_min_yval, first_legal_value);
1120 first_legal_value = min (_max_yval, first_legal_value);
1122 /* remove all events earlier than the new "front" */
1124 i = _events.begin();
1126 while (i != _events.end() && !_events.empty()) {
1127 ControlList::iterator tmp;
1132 if ((*i)->when > first_legal_coordinate) {
1142 /* shift all remaining points left to keep their same
1146 for (i = _events.begin(); i != _events.end(); ++i) {
1147 (*i)->when -= first_legal_coordinate;
1150 /* add a new point for the interpolated new value */
1152 _events.push_front (new ControlEvent (0, first_legal_value));
1155 unlocked_invalidate_insert_iterator ();
1159 maybe_signal_changed ();
1163 ControlList::unlocked_eval (double x) const
1165 pair<EventList::iterator,EventList::iterator> range;
1171 const_iterator length_check_iter = _events.begin();
1172 for (npoints = 0; npoints < 4; ++npoints, ++length_check_iter) {
1173 if (length_check_iter == _events.end()) {
1180 return _default_value;
1183 return _events.front()->value;
1186 if (x >= _events.back()->when) {
1187 return _events.back()->value;
1188 } else if (x <= _events.front()->when) {
1189 return _events.front()->value;
1192 lpos = _events.front()->when;
1193 lval = _events.front()->value;
1194 upos = _events.back()->when;
1195 uval = _events.back()->value;
1197 if (_interpolation == Discrete) {
1201 /* linear interpolation betweeen the two points */
1202 fraction = (double) (x - lpos) / (double) (upos - lpos);
1203 return lval + (fraction * (uval - lval));
1206 if (x >= _events.back()->when) {
1207 return _events.back()->value;
1208 } else if (x <= _events.front()->when) {
1209 return _events.front()->value;
1212 return multipoint_eval (x);
1215 abort(); /*NOTREACHED*/ /* stupid gcc */
1216 return _default_value;
1220 ControlList::multipoint_eval (double x) const
1226 /* "Stepped" lookup (no interpolation) */
1227 /* FIXME: no cache. significant? */
1228 if (_interpolation == Discrete) {
1229 const ControlEvent cp (x, 0);
1230 EventList::const_iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
1232 // shouldn't have made it to multipoint_eval
1233 assert(i != _events.end());
1235 if (i == _events.begin() || (*i)->when == x)
1238 return (*(--i))->value;
1241 /* Only do the range lookup if x is in a different range than last time
1242 * this was called (or if the lookup cache has been marked "dirty" (left<0) */
1243 if ((_lookup_cache.left < 0) ||
1244 ((_lookup_cache.left > x) ||
1245 (_lookup_cache.range.first == _events.end()) ||
1246 ((*_lookup_cache.range.second)->when < x))) {
1248 const ControlEvent cp (x, 0);
1250 _lookup_cache.range = equal_range (_events.begin(), _events.end(), &cp, time_comparator);
1253 pair<const_iterator,const_iterator> range = _lookup_cache.range;
1255 if (range.first == range.second) {
1257 /* x does not exist within the list as a control point */
1259 _lookup_cache.left = x;
1261 if (range.first != _events.begin()) {
1263 lpos = (*range.first)->when;
1264 lval = (*range.first)->value;
1266 /* we're before the first point */
1267 // return _default_value;
1268 return _events.front()->value;
1271 if (range.second == _events.end()) {
1272 /* we're after the last point */
1273 return _events.back()->value;
1276 upos = (*range.second)->when;
1277 uval = (*range.second)->value;
1279 /* linear interpolation betweeen the two points
1283 fraction = (double) (x - lpos) / (double) (upos - lpos);
1284 return lval + (fraction * (uval - lval));
1288 /* x is a control point in the data */
1289 _lookup_cache.left = -1;
1290 return (*range.first)->value;
1294 ControlList::build_search_cache_if_necessary (double start) const
1296 if (_events.empty()) {
1297 /* Empty, nothing to cache, move to end. */
1298 _search_cache.first = _events.end();
1299 _search_cache.left = 0;
1301 } else if ((_search_cache.left < 0) || (_search_cache.left > start)) {
1302 /* Marked dirty (left < 0), or we're too far forward, re-search. */
1304 const ControlEvent start_point (start, 0);
1306 _search_cache.first = lower_bound (_events.begin(), _events.end(), &start_point, time_comparator);
1307 _search_cache.left = start;
1310 /* We now have a search cache that is not too far right, but it may be too
1311 far left and need to be advanced. */
1313 while (_search_cache.first != end() && (*_search_cache.first)->when < start) {
1314 ++_search_cache.first;
1316 _search_cache.left = start;
1319 /** Get the earliest event after \a start using the current interpolation style.
1321 * If an event is found, \a x and \a y are set to its coordinates.
1323 * \param inclusive Include events with timestamp exactly equal to \a start
1324 * \return true if event is found (and \a x and \a y are valid).
1327 ControlList::rt_safe_earliest_event (double start, double& x, double& y, bool inclusive) const
1329 // FIXME: It would be nice if this was unnecessary..
1330 Glib::Threads::RWLock::ReaderLock lm(_lock, Glib::Threads::TRY_LOCK);
1335 return rt_safe_earliest_event_unlocked (start, x, y, inclusive);
1339 /** Get the earliest event after \a start using the current interpolation style.
1341 * If an event is found, \a x and \a y are set to its coordinates.
1343 * \param inclusive Include events with timestamp exactly equal to \a start
1344 * \return true if event is found (and \a x and \a y are valid).
1347 ControlList::rt_safe_earliest_event_unlocked (double start, double& x, double& y, bool inclusive) const
1349 if (_interpolation == Discrete) {
1350 return rt_safe_earliest_event_discrete_unlocked(start, x, y, inclusive);
1352 return rt_safe_earliest_event_linear_unlocked(start, x, y, inclusive);
1357 /** Get the earliest event after \a start without interpolation.
1359 * If an event is found, \a x and \a y are set to its coordinates.
1361 * \param inclusive Include events with timestamp exactly equal to \a start
1362 * \return true if event is found (and \a x and \a y are valid).
1365 ControlList::rt_safe_earliest_event_discrete_unlocked (double start, double& x, double& y, bool inclusive) const
1367 build_search_cache_if_necessary (start);
1369 if (_search_cache.first != _events.end()) {
1370 const ControlEvent* const first = *_search_cache.first;
1372 const bool past_start = (inclusive ? first->when >= start : first->when > start);
1374 /* Earliest points is in range, return it */
1380 /* Move left of cache to this point
1381 * (Optimize for immediate call this cycle within range) */
1382 _search_cache.left = x;
1383 ++_search_cache.first;
1392 /* No points in range */
1398 /** Get the earliest time the line crosses an integer (Linear interpolation).
1400 * If an event is found, \a x and \a y are set to its coordinates.
1402 * \param inclusive Include events with timestamp exactly equal to \a start
1403 * \return true if event is found (and \a x and \a y are valid).
1406 ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, double& y, bool inclusive) const
1408 // cout << "earliest_event(start: " << start << ", x: " << x << ", y: " << y << ", inclusive: " << inclusive << ")" << endl;
1410 const_iterator length_check_iter = _events.begin();
1411 if (_events.empty()) { // 0 events
1413 } else if (_events.end() == ++length_check_iter) { // 1 event
1414 return rt_safe_earliest_event_discrete_unlocked (start, x, y, inclusive);
1417 // Hack to avoid infinitely repeating the same event
1418 build_search_cache_if_necessary (start);
1420 if (_search_cache.first != _events.end()) {
1422 const ControlEvent* first = NULL;
1423 const ControlEvent* next = NULL;
1425 if (_search_cache.first == _events.begin() || (*_search_cache.first)->when <= start) {
1426 /* Step is after first */
1427 first = *_search_cache.first;
1428 ++_search_cache.first;
1429 if (_search_cache.first == _events.end()) {
1432 next = *_search_cache.first;
1435 /* Step is before first */
1436 const_iterator prev = _search_cache.first;
1439 next = *_search_cache.first;
1442 if (inclusive && first->when == start) {
1445 /* Move left of cache to this point
1446 * (Optimize for immediate call this cycle within range) */
1447 _search_cache.left = x;
1449 } else if (next->when < start || (!inclusive && next->when == start)) {
1450 /* "Next" is before the start, no points left. */
1454 if (fabs(first->value - next->value) <= 1) {
1455 if (next->when > start) {
1458 /* Move left of cache to this point
1459 * (Optimize for immediate call this cycle within range) */
1460 _search_cache.left = x;
1467 const double slope = (next->value - first->value) / (double)(next->when - first->when);
1468 //cerr << "start y: " << start_y << endl;
1470 //y = first->value + (slope * fabs(start - first->when));
1473 if (first->value < next->value) // ramping up
1475 else // ramping down
1478 x = first->when + (y - first->value) / (double)slope;
1480 while ((inclusive && x < start) || (x <= start && y != next->value)) {
1482 if (first->value < next->value) // ramping up
1484 else // ramping down
1487 x = first->when + (y - first->value) / (double)slope;
1490 /*cerr << first->value << " @ " << first->when << " ... "
1491 << next->value << " @ " << next->when
1492 << " = " << y << " @ " << x << endl;*/
1494 assert( (y >= first->value && y <= next->value)
1495 || (y <= first->value && y >= next->value) );
1498 const bool past_start = (inclusive ? x >= start : x > start);
1500 /* Move left of cache to this point
1501 * (Optimize for immediate call this cycle within range) */
1502 _search_cache.left = x;
1503 assert(inclusive ? x >= start : x > start);
1511 _search_cache.left = x;
1516 /* No points in the future, so no steps (towards them) in the future */
1522 /** @param start Start position in model coordinates.
1523 * @param end End position in model coordinates.
1524 * @param op 0 = cut, 1 = copy, 2 = clear.
1526 boost::shared_ptr<ControlList>
1527 ControlList::cut_copy_clear (double start, double end, int op)
1529 boost::shared_ptr<ControlList> nal = create (_parameter, _desc);
1531 ControlEvent cp (start, 0.0);
1534 Glib::Threads::RWLock::WriterLock lm (_lock);
1536 /* first, determine s & e, two iterators that define the range of points
1537 affected by this operation
1540 if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) == _events.end()) {
1544 /* and the last that is at or after `end' */
1546 e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1549 /* if "start" isn't the location of an existing point,
1550 evaluate the curve to get a value for the start. Add a point to
1551 both the existing event list, and if its not a "clear" operation,
1552 to the copy ("nal") as well.
1554 Note that the time positions of the points in each list are different
1555 because we want the copy ("nal") to have a zero time reference.
1559 /* before we begin any cut/clear operations, get the value of the curve
1563 double end_value = unlocked_eval (end);
1565 if ((*s)->when != start) {
1567 double val = unlocked_eval (start);
1569 if (op == 0) { // cut
1570 if (start > _events.front()->when) {
1571 _events.insert (s, (new ControlEvent (start, val)));
1575 if (op != 2) { // ! clear
1576 nal->_events.push_back (new ControlEvent (0, val));
1580 for (iterator x = s; x != e; ) {
1582 /* adjust new points to be relative to start, which
1583 has been set to zero.
1587 nal->_events.push_back (new ControlEvent ((*x)->when - start, (*x)->value));
1591 x = _events.erase (x);
1597 if (e == _events.end() || (*e)->when != end) {
1599 /* only add a boundary point if there is a point after "end"
1602 if (op == 0 && (e != _events.end() && end < (*e)->when)) { // cut
1603 _events.insert (e, new ControlEvent (end, end_value));
1606 if (op != 2 && (e != _events.end() && end < (*e)->when)) { // cut/copy
1607 nal->_events.push_back (new ControlEvent (end - start, end_value));
1611 unlocked_invalidate_insert_iterator ();
1616 maybe_signal_changed ();
1623 boost::shared_ptr<ControlList>
1624 ControlList::cut (double start, double end)
1626 return cut_copy_clear (start, end, 0);
1629 boost::shared_ptr<ControlList>
1630 ControlList::copy (double start, double end)
1632 return cut_copy_clear (start, end, 1);
1636 ControlList::clear (double start, double end)
1638 cut_copy_clear (start, end, 2);
1641 /** @param pos Position in model coordinates */
1643 ControlList::paste (const ControlList& alist, double pos, float /*times*/)
1645 if (alist._events.empty()) {
1650 Glib::Threads::RWLock::WriterLock lm (_lock);
1654 ControlEvent cp (pos, 0.0);
1656 where = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1658 for (const_iterator i = alist.begin();i != alist.end(); ++i) {
1659 double value = (*i)->value;
1660 if (alist.parameter() != parameter()) {
1661 const ParameterDescriptor& src_desc = alist.descriptor();
1663 value -= src_desc.lower; // translate to 0-relative
1664 value /= (src_desc.upper - src_desc.lower); // normalize range
1665 value *= (_desc.upper - _desc.lower); // scale to our range
1666 value += _desc.lower; // translate to our offset
1667 if (_desc.toggled) {
1668 value = (value < 0.5) ? 0.0 : 1.0;
1671 _events.insert (where, new ControlEvent((*i)->when + pos, value));
1672 end = (*i)->when + pos;
1676 /* move all points after the insertion along the timeline by
1680 while (where != _events.end()) {
1682 if ((*where)->when <= end) {
1685 _events.erase(where);
1693 unlocked_invalidate_insert_iterator ();
1697 maybe_signal_changed ();
1701 /** Move automation around according to a list of region movements.
1702 * @param return true if anything was changed, otherwise false (ie nothing needed changing)
1705 ControlList::move_ranges (const list< RangeMove<double> >& movements)
1707 typedef list< RangeMove<double> > RangeMoveList;
1710 Glib::Threads::RWLock::WriterLock lm (_lock);
1712 /* a copy of the events list before we started moving stuff around */
1713 EventList old_events = _events;
1715 /* clear the source and destination ranges in the new list */
1716 bool things_erased = false;
1717 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1719 if (erase_range_internal (i->from, i->from + i->length, _events)) {
1720 things_erased = true;
1723 if (erase_range_internal (i->to, i->to + i->length, _events)) {
1724 things_erased = true;
1728 /* if nothing was erased, there is nothing to do */
1729 if (!things_erased) {
1733 /* copy the events into the new list */
1734 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1735 iterator j = old_events.begin ();
1736 const double limit = i->from + i->length;
1737 const double dx = i->to - i->from;
1738 while (j != old_events.end () && (*j)->when <= limit) {
1739 if ((*j)->when >= i->from) {
1740 ControlEvent* ev = new ControlEvent (**j);
1742 _events.push_back (ev);
1749 _events.sort (event_time_less_than);
1750 unlocked_invalidate_insert_iterator ();
1752 _sort_pending = true;
1758 maybe_signal_changed ();
1763 ControlList::set_interpolation (InterpolationStyle s)
1765 if (_interpolation == s) {
1770 InterpolationChanged (s); /* EMIT SIGNAL */
1774 ControlList::operator!= (ControlList const & other) const
1776 if (_events.size() != other._events.size()) {
1780 EventList::const_iterator i = _events.begin ();
1781 EventList::const_iterator j = other._events.begin ();
1783 while (i != _events.end() && (*i)->when == (*j)->when && (*i)->value == (*j)->value) {
1788 if (i != _events.end ()) {
1793 _parameter != other._parameter ||
1794 _interpolation != other._interpolation ||
1795 _min_yval != other._min_yval ||
1796 _max_yval != other._max_yval ||
1797 _default_value != other._default_value
1802 ControlList::dump (ostream& o)
1804 /* NOT LOCKED ... for debugging only */
1806 for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
1807 o << (*x)->value << " @ " << (uint64_t) (*x)->when << endl;
1811 } // namespace Evoral