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));
339 ControlList::invalidate_insert_iterator ()
341 Glib::Threads::Mutex::Lock lm (_lock);
342 unlocked_invalidate_insert_iterator ();
346 ControlList::unlocked_invalidate_insert_iterator ()
348 most_recent_insert_iterator = _events.end();
352 ControlList::start_write_pass (double when)
354 Glib::Threads::Mutex::Lock lm (_lock);
356 DEBUG_TRACE (DEBUG::ControlList, string_compose ("%1: setup write pass @ %2\n", this, when));
358 new_write_pass = true;
359 did_write_during_pass = false;
360 insert_position = when;
362 /* leave the insert iterator invalid, so that we will do the lookup
363 of where it should be in a "lazy" way - deferring it until
364 we actually add the first point (which may never happen).
367 unlocked_invalidate_insert_iterator ();
371 ControlList::write_pass_finished (double /*when*/, double thinning_factor)
373 DEBUG_TRACE (DEBUG::ControlList, "write pass finished\n");
375 if (did_write_during_pass) {
376 thin (thinning_factor);
377 did_write_during_pass = false;
379 new_write_pass = true;
380 _in_write_pass = false;
384 ControlList::set_in_write_pass (bool yn, bool add_point, double when)
386 DEBUG_TRACE (DEBUG::ControlList, string_compose ("now in write pass @ %1, add point ? %2\n", when, add_point));
390 if (yn && add_point) {
391 add_guard_point (when);
396 ControlList::add_guard_point (double when)
398 ControlEvent cp (when, 0.0);
399 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
401 double eval_value = unlocked_eval (insert_position);
403 if (most_recent_insert_iterator == _events.end()) {
405 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert iterator at end, adding eval-value there %2\n", this, eval_value));
406 _events.push_back (new ControlEvent (when, eval_value));
407 /* leave insert iterator at the end */
409 } else if ((*most_recent_insert_iterator)->when == when) {
411 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert iterator at existing point, setting eval-value there %2\n", this, eval_value));
413 /* most_recent_insert_iterator points to a control event
414 already at the insert position, so there is
419 advance most_recent_insert_iterator so that the "real"
420 insert occurs in the right place, since it
421 points to the control event just inserted.
424 ++most_recent_insert_iterator;
427 /* insert a new control event at the right spot
430 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert eval-value %2 just before iterator @ %3\n",
431 this, eval_value, (*most_recent_insert_iterator)->when));
433 most_recent_insert_iterator = _events.insert (most_recent_insert_iterator, new ControlEvent (when, eval_value));
435 /* advance most_recent_insert_iterator so that the "real"
436 * insert occurs in the right place, since it
437 * points to the control event just inserted.
440 ++most_recent_insert_iterator;
443 /* don't do this again till the next write pass */
445 new_write_pass = false;
449 ControlList::in_write_pass () const
451 return _in_write_pass;
455 ControlList::editor_add (double when, double value)
457 /* this is for making changes from a graphical line editor
460 if (_events.empty()) {
462 /* as long as the point we're adding is not at zero,
463 * add an "anchor" point there.
467 _events.insert (_events.end(), new ControlEvent (0, _default_value));
468 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _default_value));
472 ControlEvent cp (when, 0.0f);
473 iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
474 DEBUG_TRACE (DEBUG::ControlList, string_compose ("editor_add: actually add when= %1 value= %2\n", when, value));
475 _events.insert (i, new ControlEvent (when, value));
479 maybe_signal_changed ();
484 ControlList::maybe_add_insert_guard (double when)
486 if (most_recent_insert_iterator != _events.end()) {
487 if ((*most_recent_insert_iterator)->when - when > 64) {
488 /* Next control point is some distance from where our new point is
489 going to go, so add a new point to avoid changing the shape of
490 the line too much. The insert iterator needs to point to the
491 new control point so that our insert will happen correctly. */
492 most_recent_insert_iterator = _events.insert (
493 most_recent_insert_iterator,
494 new ControlEvent (when + 1, (*most_recent_insert_iterator)->value));
495 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added insert guard point @ %2 = %3\n",
497 (*most_recent_insert_iterator)->value));
502 /** If we would just be adding to a straight line, move the previous point instead. */
504 ControlList::maybe_insert_straight_line (double when, double value)
506 if (_events.empty()) {
510 if (_events.back()->value == value) {
511 // Point b at the final point, which we know exists
512 EventList::iterator b = _events.end();
514 if (b == _events.begin()) {
515 return false; // No previous point
518 // Check the previous point's value
520 if ((*b)->value == value) {
521 /* At least two points with the exact same value (straight
522 line), just move the final point to the new time. */
523 _events.back()->when = when;
524 DEBUG_TRACE (DEBUG::ControlList, string_compose ("final value of %1 moved to %2\n", value, when));
531 ControlList::iterator
532 ControlList::erase_from_iterator_to (iterator iter, double when)
534 while (iter != _events.end()) {
535 if ((*iter)->when < when) {
536 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 erase existing @ %2\n", this, (*iter)->when));
538 iter = _events.erase (iter);
540 } else if ((*iter)->when >= when) {
549 ControlList::add (double when, double value, bool with_guards, bool with_default)
551 /* this is for making changes from some kind of user interface or
552 control surface (GUI, MIDI, OSC etc)
555 DEBUG_TRACE (DEBUG::ControlList,
556 string_compose ("@%1 add %2 at %3 guards = %4 write pass = %5 (new? %6) at end? %7\n",
557 this, value, when, with_guards, _in_write_pass, new_write_pass,
558 (most_recent_insert_iterator == _events.end())));
560 Glib::Threads::Mutex::Lock lm (_lock);
561 ControlEvent cp (when, 0.0f);
562 iterator insertion_point;
564 if (_events.empty() && with_default) {
566 /* empty: add an "anchor" point if the point we're adding past time 0 */
569 _events.insert (_events.end(), new ControlEvent (0, _default_value));
570 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _default_value));
574 if (_in_write_pass && new_write_pass) {
576 /* first write in a write pass: add guard point if requested */
579 add_guard_point (insert_position);
580 did_write_during_pass = true;
582 /* not adding a guard, but we need to set iterator appropriately */
583 const ControlEvent cp (when, 0.0);
584 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
586 new_write_pass = false;
588 } else if (_in_write_pass &&
589 (most_recent_insert_iterator == _events.end() || when > (*most_recent_insert_iterator)->when)) {
591 /* in write pass: erase from most recent insert to now */
593 if (most_recent_insert_iterator != _events.end()) {
594 /* advance to avoid deleting the last inserted point itself. */
595 ++most_recent_insert_iterator;
598 most_recent_insert_iterator = erase_from_iterator_to(most_recent_insert_iterator, when);
600 maybe_add_insert_guard (when);
603 } else if (!_in_write_pass) {
605 /* not in a write pass: figure out the iterator we should insert in front of */
607 DEBUG_TRACE (DEBUG::ControlList, string_compose ("compute(b) MRI for position %1\n", when));
608 ControlEvent cp (when, 0.0f);
609 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
612 /* OK, now we're really ready to add a new point */
614 if (most_recent_insert_iterator == _events.end()) {
615 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 appending new point at end\n", this));
617 const bool done = maybe_insert_straight_line (when, value);
619 _events.push_back (new ControlEvent (when, value));
620 DEBUG_TRACE (DEBUG::ControlList, string_compose ("\tactually appended, size now %1\n", _events.size()));
623 most_recent_insert_iterator = _events.end();
624 --most_recent_insert_iterator;
626 } else if ((*most_recent_insert_iterator)->when == when) {
628 if ((*most_recent_insert_iterator)->value != value) {
629 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 reset existing point to new value %2\n", this, value));
631 /* only one point allowed per time point, so just
632 * reset the value here.
635 (*most_recent_insert_iterator)->value = value;
637 /* if we modified the final value, then its as
638 * if we inserted a new point as far as the
639 * next addition, so make sure we know that.
642 if (_events.back()->when == when) {
643 most_recent_insert_iterator = _events.end();
647 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 same time %2, same value value %3\n", this, when, value));
651 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert new point at %2 at iterator at %3\n", this, when, (*most_recent_insert_iterator)->when));
653 const bool done = maybe_insert_straight_line (when, value);
655 maybe_add_insert_guard(when);
659 EventList::iterator x = _events.insert (most_recent_insert_iterator, new ControlEvent (when, value));
660 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 inserted new value before MRI, size now %2\n", this, _events.size()));
661 most_recent_insert_iterator = x;
668 maybe_signal_changed ();
672 ControlList::erase (iterator i)
675 Glib::Threads::Mutex::Lock lm (_lock);
676 if (most_recent_insert_iterator == i) {
677 unlocked_invalidate_insert_iterator ();
682 maybe_signal_changed ();
686 ControlList::erase (iterator start, iterator end)
689 Glib::Threads::Mutex::Lock lm (_lock);
690 _events.erase (start, end);
691 unlocked_invalidate_insert_iterator ();
694 maybe_signal_changed ();
697 /** Erase the first event which matches the given time and value */
699 ControlList::erase (double when, double value)
702 Glib::Threads::Mutex::Lock lm (_lock);
704 iterator i = begin ();
705 while (i != end() && ((*i)->when != when || (*i)->value != value)) {
711 if (most_recent_insert_iterator == i) {
712 unlocked_invalidate_insert_iterator ();
719 maybe_signal_changed ();
723 ControlList::erase_range (double start, double endt)
728 Glib::Threads::Mutex::Lock lm (_lock);
729 erased = erase_range_internal (start, endt, _events);
738 maybe_signal_changed ();
743 ControlList::erase_range_internal (double start, double endt, EventList & events)
746 ControlEvent cp (start, 0.0f);
750 if ((s = lower_bound (events.begin(), events.end(), &cp, time_comparator)) != events.end()) {
752 e = upper_bound (events.begin(), events.end(), &cp, time_comparator);
755 unlocked_invalidate_insert_iterator ();
764 ControlList::slide (iterator before, double distance)
767 Glib::Threads::Mutex::Lock lm (_lock);
769 if (before == _events.end()) {
773 while (before != _events.end()) {
774 (*before)->when += distance;
781 maybe_signal_changed ();
785 ControlList::shift (double pos, double frames)
788 Glib::Threads::Mutex::Lock lm (_lock);
790 for (iterator i = _events.begin(); i != _events.end(); ++i) {
791 if ((*i)->when >= pos) {
792 (*i)->when += frames;
799 maybe_signal_changed ();
803 ControlList::modify (iterator iter, double when, double val)
805 /* note: we assume higher level logic is in place to avoid this
806 reordering the time-order of control events in the list. ie. all
807 points after *iter are later than when.
811 Glib::Threads::Mutex::Lock lm (_lock);
813 (*iter)->when = when;
814 (*iter)->value = val;
815 if (isnan_local (val)) {
820 _events.sort (event_time_less_than);
821 unlocked_invalidate_insert_iterator ();
823 _sort_pending = true;
829 maybe_signal_changed ();
832 std::pair<ControlList::iterator,ControlList::iterator>
833 ControlList::control_points_adjacent (double xval)
835 Glib::Threads::Mutex::Lock lm (_lock);
837 ControlEvent cp (xval, 0.0f);
838 std::pair<iterator,iterator> ret;
840 ret.first = _events.end();
841 ret.second = _events.end();
843 for (i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator); i != _events.end(); ++i) {
845 if (ret.first == _events.end()) {
846 if ((*i)->when >= xval) {
847 if (i != _events.begin()) {
856 if ((*i)->when > xval) {
866 ControlList::freeze ()
881 Glib::Threads::Mutex::Lock lm (_lock);
884 _events.sort (event_time_less_than);
885 unlocked_invalidate_insert_iterator ();
886 _sort_pending = false;
892 ControlList::mark_dirty () const
894 _lookup_cache.left = -1;
895 _lookup_cache.range.first = _events.end();
896 _lookup_cache.range.second = _events.end();
897 _search_cache.left = -1;
898 _search_cache.first = _events.end();
901 _curve->mark_dirty();
904 Dirty (); /* EMIT SIGNAL */
908 ControlList::truncate_end (double last_coordinate)
911 Glib::Threads::Mutex::Lock lm (_lock);
912 ControlEvent cp (last_coordinate, 0);
913 ControlList::reverse_iterator i;
916 if (_events.empty()) {
920 if (last_coordinate == _events.back()->when) {
924 if (last_coordinate > _events.back()->when) {
929 iterator foo = _events.begin();
932 if (foo == _events.end()) {
934 } else if (++foo == _events.end()) {
941 /* less than 2 points: add a new point */
942 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
945 /* more than 2 points: check to see if the last 2 values
946 are equal. if so, just move the position of the
947 last point. otherwise, add a new point.
950 iterator penultimate = _events.end();
951 --penultimate; /* points at last point */
952 --penultimate; /* points at the penultimate point */
954 if (_events.back()->value == (*penultimate)->value) {
955 _events.back()->when = last_coordinate;
957 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
965 last_val = unlocked_eval (last_coordinate);
966 last_val = max ((double) _min_yval, last_val);
967 last_val = min ((double) _max_yval, last_val);
969 i = _events.rbegin();
971 /* make i point to the last control point */
975 /* now go backwards, removing control points that are
976 beyond the new last coordinate.
979 // FIXME: SLOW! (size() == O(n))
981 uint32_t sz = _events.size();
983 while (i != _events.rend() && sz > 2) {
984 ControlList::reverse_iterator tmp;
989 if ((*i)->when < last_coordinate) {
993 _events.erase (i.base());
999 _events.back()->when = last_coordinate;
1000 _events.back()->value = last_val;
1003 unlocked_invalidate_insert_iterator ();
1007 maybe_signal_changed ();
1011 ControlList::truncate_start (double overall_length)
1014 Glib::Threads::Mutex::Lock lm (_lock);
1016 double first_legal_value;
1017 double first_legal_coordinate;
1019 if (_events.empty()) {
1020 /* nothing to truncate */
1022 } else 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