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::RWLock::WriterLock 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::RWLock::WriterLock lm (_lock);
219 unlocked_invalidate_insert_iterator ();
223 maybe_signal_changed ();
227 ControlList::x_scale (double factor)
229 Glib::Threads::RWLock::WriterLock lm (_lock);
234 ControlList::extend_to (double when)
236 Glib::Threads::RWLock::WriterLock 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::RWLock::WriterLock 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::RWLock::WriterLock 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::RWLock::WriterLock 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::RWLock::WriterLock 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, bool with_guard)
457 /* this is for making changes from a graphical line editor
460 ControlEvent cp (when, 0.0f);
461 iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
463 if (i != _events.end () && (*i)->when == when) {
467 if (_events.empty()) {
469 /* as long as the point we're adding is not at zero,
470 * add an "anchor" point there.
474 _events.insert (_events.end(), new ControlEvent (0, value));
475 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added value %2 at zero\n", this, value));
479 insert_position = when;
482 add_guard_point (when - 64);
484 maybe_add_insert_guard (when);
488 DEBUG_TRACE (DEBUG::ControlList, string_compose ("editor_add: actually add when= %1 value= %2\n", when, value));
489 result = _events.insert (i, new ControlEvent (when, value));
496 maybe_signal_changed ();
502 ControlList::maybe_add_insert_guard (double when)
504 if (most_recent_insert_iterator != _events.end()) {
505 if ((*most_recent_insert_iterator)->when - when > 64) {
506 /* Next control point is some distance from where our new point is
507 going to go, so add a new point to avoid changing the shape of
508 the line too much. The insert iterator needs to point to the
509 new control point so that our insert will happen correctly. */
510 most_recent_insert_iterator = _events.insert (
511 most_recent_insert_iterator,
512 new ControlEvent (when + 64, (*most_recent_insert_iterator)->value));
513 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added insert guard point @ %2 = %3\n",
515 (*most_recent_insert_iterator)->value));
520 /** If we would just be adding to a straight line, move the previous point instead. */
522 ControlList::maybe_insert_straight_line (double when, double value)
524 if (_events.empty()) {
528 if (_events.back()->value == value) {
529 // Point b at the final point, which we know exists
530 EventList::iterator b = _events.end();
532 if (b == _events.begin()) {
533 return false; // No previous point
536 // Check the previous point's value
538 if ((*b)->value == value) {
539 /* At least two points with the exact same value (straight
540 line), just move the final point to the new time. */
541 _events.back()->when = when;
542 DEBUG_TRACE (DEBUG::ControlList, string_compose ("final value of %1 moved to %2\n", value, when));
549 ControlList::iterator
550 ControlList::erase_from_iterator_to (iterator iter, double when)
552 while (iter != _events.end()) {
553 if ((*iter)->when < when) {
554 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 erase existing @ %2\n", this, (*iter)->when));
556 iter = _events.erase (iter);
558 } else if ((*iter)->when >= when) {
567 ControlList::add (double when, double value, bool with_guards, bool with_initial)
569 /* this is for making changes from some kind of user interface or
570 control surface (GUI, MIDI, OSC etc)
573 DEBUG_TRACE (DEBUG::ControlList,
574 string_compose ("@%1 add %2 at %3 guards = %4 write pass = %5 (new? %6) at end? %7\n",
575 this, value, when, with_guards, _in_write_pass, new_write_pass,
576 (most_recent_insert_iterator == _events.end())));
578 Glib::Threads::RWLock::WriterLock lm (_lock);
579 ControlEvent cp (when, 0.0f);
580 iterator insertion_point;
582 if (_events.empty() && with_initial) {
584 /* empty: add an "anchor" point if the point we're adding past time 0 */
588 const bool bval = ((value >= 0.5) ? true : false);
589 _events.insert (_events.end(), new ControlEvent (0, !bval));
590 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added bool value %2 at zero\n", this, !bval));
593 _events.insert (_events.end(), new ControlEvent (0, value));
594 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _default_value));
599 if (_in_write_pass && new_write_pass) {
601 /* first write in a write pass: add guard point if requested */
604 add_guard_point (insert_position);
605 did_write_during_pass = true;
607 /* not adding a guard, but we need to set iterator appropriately */
608 const ControlEvent cp (when, 0.0);
609 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
611 new_write_pass = false;
613 } else if (_in_write_pass &&
614 (most_recent_insert_iterator == _events.end() || when > (*most_recent_insert_iterator)->when)) {
616 /* in write pass: erase from most recent insert to now */
618 if (most_recent_insert_iterator != _events.end()) {
619 /* advance to avoid deleting the last inserted point itself. */
620 ++most_recent_insert_iterator;
623 most_recent_insert_iterator = erase_from_iterator_to(most_recent_insert_iterator, when);
625 maybe_add_insert_guard (when);
628 } else if (!_in_write_pass) {
630 /* not in a write pass: figure out the iterator we should insert in front of */
632 DEBUG_TRACE (DEBUG::ControlList, string_compose ("compute(b) MRI for position %1\n", when));
633 ControlEvent cp (when, 0.0f);
634 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
637 /* OK, now we're really ready to add a new point */
639 if (most_recent_insert_iterator == _events.end()) {
640 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 appending new point at end\n", this));
642 const bool done = maybe_insert_straight_line (when, value);
644 _events.push_back (new ControlEvent (when, value));
645 DEBUG_TRACE (DEBUG::ControlList, string_compose ("\tactually appended, size now %1\n", _events.size()));
648 most_recent_insert_iterator = _events.end();
649 --most_recent_insert_iterator;
651 } else if ((*most_recent_insert_iterator)->when == when) {
653 if ((*most_recent_insert_iterator)->value != value) {
654 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 reset existing point to new value %2\n", this, value));
656 /* only one point allowed per time point, so add a guard point
657 * before it if needed then reset the value of the point.
660 (*most_recent_insert_iterator)->value = value;
662 /* if we modified the final value, then its as
663 * if we inserted a new point as far as the
664 * next addition, so make sure we know that.
667 if (_events.back()->when == when) {
668 most_recent_insert_iterator = _events.end();
672 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 same time %2, same value value %3\n", this, when, value));
676 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert new point at %2 at iterator at %3\n", this, when, (*most_recent_insert_iterator)->when));
678 /* check for possible straight line here until maybe_insert_straight_line () handles the insert iterator properly*/
679 if (most_recent_insert_iterator != _events.begin ()) {
680 bool have_point2 = false;
681 --most_recent_insert_iterator;
682 const bool have_point1 = (*most_recent_insert_iterator)->value == value;
684 if (most_recent_insert_iterator != _events.begin ()) {
685 --most_recent_insert_iterator;
686 have_point2 = (*most_recent_insert_iterator)->value == value;
687 ++most_recent_insert_iterator;
690 if (have_point1 && have_point2) {
691 (*most_recent_insert_iterator)->when = when;
694 ++most_recent_insert_iterator;
697 //done = maybe_insert_straight_line (when, value) || done;
698 /* if the transport is stopped, add guard points (?) */
699 if (!done && !_in_write_pass && when > 64) {
700 add_guard_point (when - 64);
701 maybe_add_insert_guard (when);
705 maybe_add_insert_guard (when);
709 EventList::iterator x = _events.insert (most_recent_insert_iterator, new ControlEvent (when, value));
710 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 inserted new value before MRI, size now %2\n", this, _events.size()));
711 most_recent_insert_iterator = x;
718 maybe_signal_changed ();
722 ControlList::erase (iterator i)
725 Glib::Threads::RWLock::WriterLock lm (_lock);
726 if (most_recent_insert_iterator == i) {
727 unlocked_invalidate_insert_iterator ();
732 maybe_signal_changed ();
736 ControlList::erase (iterator start, iterator end)
739 Glib::Threads::RWLock::WriterLock lm (_lock);
740 _events.erase (start, end);
741 unlocked_invalidate_insert_iterator ();
744 maybe_signal_changed ();
747 /** Erase the first event which matches the given time and value */
749 ControlList::erase (double when, double value)
752 Glib::Threads::RWLock::WriterLock lm (_lock);
754 iterator i = begin ();
755 while (i != end() && ((*i)->when != when || (*i)->value != value)) {
761 if (most_recent_insert_iterator == i) {
762 unlocked_invalidate_insert_iterator ();
769 maybe_signal_changed ();
773 ControlList::erase_range (double start, double endt)
778 Glib::Threads::RWLock::WriterLock lm (_lock);
779 erased = erase_range_internal (start, endt, _events);
788 maybe_signal_changed ();
793 ControlList::erase_range_internal (double start, double endt, EventList & events)
796 ControlEvent cp (start, 0.0f);
800 if ((s = lower_bound (events.begin(), events.end(), &cp, time_comparator)) != events.end()) {
802 e = upper_bound (events.begin(), events.end(), &cp, time_comparator);
805 unlocked_invalidate_insert_iterator ();
814 ControlList::slide (iterator before, double distance)
817 Glib::Threads::RWLock::WriterLock lm (_lock);
819 if (before == _events.end()) {
823 while (before != _events.end()) {
824 (*before)->when += distance;
831 maybe_signal_changed ();
835 ControlList::shift (double pos, double frames)
838 Glib::Threads::RWLock::WriterLock lm (_lock);
840 for (iterator i = _events.begin(); i != _events.end(); ++i) {
841 if ((*i)->when >= pos) {
842 (*i)->when += frames;
849 maybe_signal_changed ();
853 ControlList::modify (iterator iter, double when, double val)
855 /* note: we assume higher level logic is in place to avoid this
856 reordering the time-order of control events in the list. ie. all
857 points after *iter are later than when.
861 Glib::Threads::RWLock::WriterLock lm (_lock);
863 (*iter)->when = when;
864 (*iter)->value = val;
865 if (isnan_local (val)) {
870 _events.sort (event_time_less_than);
871 unlocked_invalidate_insert_iterator ();
873 _sort_pending = true;
879 maybe_signal_changed ();
882 std::pair<ControlList::iterator,ControlList::iterator>
883 ControlList::control_points_adjacent (double xval)
885 Glib::Threads::RWLock::ReaderLock lm (_lock);
887 ControlEvent cp (xval, 0.0f);
888 std::pair<iterator,iterator> ret;
890 ret.first = _events.end();
891 ret.second = _events.end();
893 for (i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator); i != _events.end(); ++i) {
895 if (ret.first == _events.end()) {
896 if ((*i)->when >= xval) {
897 if (i != _events.begin()) {
906 if ((*i)->when > xval) {
916 ControlList::freeze ()
931 Glib::Threads::RWLock::WriterLock lm (_lock);
934 _events.sort (event_time_less_than);
935 unlocked_invalidate_insert_iterator ();
936 _sort_pending = false;
942 ControlList::mark_dirty () const
944 _lookup_cache.left = -1;
945 _lookup_cache.range.first = _events.end();
946 _lookup_cache.range.second = _events.end();
947 _search_cache.left = -1;
948 _search_cache.first = _events.end();
951 _curve->mark_dirty();
954 Dirty (); /* EMIT SIGNAL */
958 ControlList::truncate_end (double last_coordinate)
961 Glib::Threads::RWLock::WriterLock lm (_lock);
962 ControlEvent cp (last_coordinate, 0);
963 ControlList::reverse_iterator i;
966 if (_events.empty()) {
970 if (last_coordinate == _events.back()->when) {
974 if (last_coordinate > _events.back()->when) {
979 iterator foo = _events.begin();
982 if (foo == _events.end()) {
984 } else if (++foo == _events.end()) {
991 /* less than 2 points: add a new point */
992 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
995 /* more than 2 points: check to see if the last 2 values
996 are equal. if so, just move the position of the
997 last point. otherwise, add a new point.
1000 iterator penultimate = _events.end();
1001 --penultimate; /* points at last point */
1002 --penultimate; /* points at the penultimate point */
1004 if (_events.back()->value == (*penultimate)->value) {
1005 _events.back()->when = last_coordinate;
1007 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
1013 /* shortening end */
1015 last_val = unlocked_eval (last_coordinate);
1016 last_val = max ((double) _min_yval, last_val);
1017 last_val = min ((double) _max_yval, last_val);
1019 i = _events.rbegin();
1021 /* make i point to the last control point */
1025 /* now go backwards, removing control points that are
1026 beyond the new last coordinate.
1029 // FIXME: SLOW! (size() == O(n))
1031 uint32_t sz = _events.size();
1033 while (i != _events.rend() && sz > 2) {
1034 ControlList::reverse_iterator tmp;
1039 if ((*i)->when < last_coordinate) {
1043 _events.erase (i.base());
1049 _events.back()->when = last_coordinate;
1050 _events.back()->value = last_val;
1053 unlocked_invalidate_insert_iterator ();
1057 maybe_signal_changed ();
1061 ControlList::truncate_start (double overall_length)
1064 Glib::Threads::RWLock::WriterLock lm (_lock);
1066 double first_legal_value;
1067 double first_legal_coordinate;
1069 if (_events.empty()) {
1070 /* nothing to truncate */
1072 } else if (overall_length == _events.back()->when) {
1073 /* no change in overall length */
1077 if (overall_length > _events.back()->when) {
1079 /* growing at front: duplicate first point. shift all others */
1081 double shift = overall_length - _events.back()->when;
1084 for (np = 0, i = _events.begin(); i != _events.end(); ++i, ++np) {
1085 (*i)->when += shift;
1090 /* less than 2 points: add a new point */
1091 _events.push_front (new ControlEvent (0, _events.front()->value));
1095 /* more than 2 points: check to see if the first 2 values
1096 are equal. if so, just move the position of the
1097 first point. otherwise, add a new point.
1100 iterator second = _events.begin();
1101 ++second; /* points at the second point */
1103 if (_events.front()->value == (*second)->value) {
1104 /* first segment is flat, just move start point back to zero */
1105 _events.front()->when = 0;
1107 /* leave non-flat segment in place, add a new leading point. */
1108 _events.push_front (new ControlEvent (0, _events.front()->value));
1114 /* shrinking at front */
1116 first_legal_coordinate = _events.back()->when - overall_length;
1117 first_legal_value = unlocked_eval (first_legal_coordinate);
1118 first_legal_value = max (_min_yval, first_legal_value);
1119 first_legal_value = min (_max_yval, first_legal_value);
1121 /* remove all events earlier than the new "front" */
1123 i = _events.begin();
1125 while (i != _events.end() && !_events.empty()) {
1126 ControlList::iterator tmp;
1131 if ((*i)->when > first_legal_coordinate) {
1141 /* shift all remaining points left to keep their same
1145 for (i = _events.begin(); i != _events.end(); ++i) {
1146 (*i)->when -= first_legal_coordinate;
1149 /* add a new point for the interpolated new value */
1151 _events.push_front (new ControlEvent (0, first_legal_value));
1154 unlocked_invalidate_insert_iterator ();
1158 maybe_signal_changed ();
1162 ControlList::unlocked_eval (double x) const
1164 pair<EventList::iterator,EventList::iterator> range;
1170 const_iterator length_check_iter = _events.begin();
1171 for (npoints = 0; npoints < 4; ++npoints, ++length_check_iter) {
1172 if (length_check_iter == _events.end()) {
1179 return _default_value;
1182 return _events.front()->value;
1185 if (x >= _events.back()->when) {
1186 return _events.back()->value;
1187 } else if (x <= _events.front()->when) {
1188 return _events.front()->value;
1191 lpos = _events.front()->when;
1192 lval = _events.front()->value;
1193 upos = _events.back()->when;
1194 uval = _events.back()->value;
1196 if (_interpolation == Discrete) {
1200 /* linear interpolation betweeen the two points */
1201 fraction = (double) (x - lpos) / (double) (upos - lpos);
1202 return lval + (fraction * (uval - lval));
1205 if (x >= _events.back()->when) {
1206 return _events.back()->value;
1207 } else if (x <= _events.front()->when) {
1208 return _events.front()->value;
1211 return multipoint_eval (x);
1214 abort(); /*NOTREACHED*/ /* stupid gcc */
1215 return _default_value;
1219 ControlList::multipoint_eval (double x) const
1225 /* "Stepped" lookup (no interpolation) */
1226 /* FIXME: no cache. significant? */
1227 if (_interpolation == Discrete) {
1228 const ControlEvent cp (x, 0);
1229 EventList::const_iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
1231 // shouldn't have made it to multipoint_eval
1232 assert(i != _events.end());
1234 if (i == _events.begin() || (*i)->when == x)
1237 return (*(--i))->value;
1240 /* Only do the range lookup if x is in a different range than last time
1241 * this was called (or if the lookup cache has been marked "dirty" (left<0) */
1242 if ((_lookup_cache.left < 0) ||
1243 ((_lookup_cache.left > x) ||
1244 (_lookup_cache.range.first == _events.end()) ||
1245 ((*_lookup_cache.range.second)->when < x))) {
1247 const ControlEvent cp (x, 0);
1249 _lookup_cache.range = equal_range (_events.begin(), _events.end(), &cp, time_comparator);
1252 pair<const_iterator,const_iterator> range = _lookup_cache.range;
1254 if (range.first == range.second) {
1256 /* x does not exist within the list as a control point */
1258 _lookup_cache.left = x;
1260 if (range.first != _events.begin()) {
1262 lpos = (*range.first)->when;
1263 lval = (*range.first)->value;
1265 /* we're before the first point */
1266 // return _default_value;
1267 return _events.front()->value;
1270 if (range.second == _events.end()) {
1271 /* we're after the last point */
1272 return _events.back()->value;
1275 upos = (*range.second)->when;
1276 uval = (*range.second)->value;
1278 /* linear interpolation betweeen the two points
1282 fraction = (double) (x - lpos) / (double) (upos - lpos);
1283 return lval + (fraction * (uval - lval));
1287 /* x is a control point in the data */
1288 _lookup_cache.left = -1;
1289 return (*range.first)->value;
1293 ControlList::build_search_cache_if_necessary (double start) const
1295 if (_events.empty()) {
1296 /* Empty, nothing to cache, move to end. */
1297 _search_cache.first = _events.end();
1298 _search_cache.left = 0;
1300 } else if ((_search_cache.left < 0) || (_search_cache.left > start)) {
1301 /* Marked dirty (left < 0), or we're too far forward, re-search. */
1303 const ControlEvent start_point (start, 0);
1305 _search_cache.first = lower_bound (_events.begin(), _events.end(), &start_point, time_comparator);
1306 _search_cache.left = start;
1309 /* We now have a search cache that is not too far right, but it may be too
1310 far left and need to be advanced. */
1312 while (_search_cache.first != end() && (*_search_cache.first)->when < start) {
1313 ++_search_cache.first;
1315 _search_cache.left = start;
1318 /** Get the earliest event after \a start using the current interpolation style.
1320 * If an event is found, \a x and \a y are set to its coordinates.
1322 * \param inclusive Include events with timestamp exactly equal to \a start
1323 * \return true if event is found (and \a x and \a y are valid).
1326 ControlList::rt_safe_earliest_event (double start, double& x, double& y, bool inclusive) const
1328 // FIXME: It would be nice if this was unnecessary..
1329 Glib::Threads::RWLock::ReaderLock lm(_lock, Glib::Threads::TRY_LOCK);
1334 return rt_safe_earliest_event_unlocked (start, x, y, inclusive);
1338 /** Get the earliest event after \a start using the current interpolation style.
1340 * If an event is found, \a x and \a y are set to its coordinates.
1342 * \param inclusive Include events with timestamp exactly equal to \a start
1343 * \return true if event is found (and \a x and \a y are valid).
1346 ControlList::rt_safe_earliest_event_unlocked (double start, double& x, double& y, bool inclusive) const
1348 if (_interpolation == Discrete) {
1349 return rt_safe_earliest_event_discrete_unlocked(start, x, y, inclusive);
1351 return rt_safe_earliest_event_linear_unlocked(start, x, y, inclusive);
1356 /** Get the earliest event after \a start without interpolation.
1358 * If an event is found, \a x and \a y are set to its coordinates.
1360 * \param inclusive Include events with timestamp exactly equal to \a start
1361 * \return true if event is found (and \a x and \a y are valid).
1364 ControlList::rt_safe_earliest_event_discrete_unlocked (double start, double& x, double& y, bool inclusive) const
1366 build_search_cache_if_necessary (start);
1368 if (_search_cache.first != _events.end()) {
1369 const ControlEvent* const first = *_search_cache.first;
1371 const bool past_start = (inclusive ? first->when >= start : first->when > start);
1373 /* Earliest points is in range, return it */
1379 /* Move left of cache to this point
1380 * (Optimize for immediate call this cycle within range) */
1381 _search_cache.left = x;
1382 ++_search_cache.first;
1391 /* No points in range */
1397 /** Get the earliest time the line crosses an integer (Linear interpolation).
1399 * If an event is found, \a x and \a y are set to its coordinates.
1401 * \param inclusive Include events with timestamp exactly equal to \a start
1402 * \return true if event is found (and \a x and \a y are valid).
1405 ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, double& y, bool inclusive) const
1407 // cout << "earliest_event(start: " << start << ", x: " << x << ", y: " << y << ", inclusive: " << inclusive << ")" << endl;
1409 const_iterator length_check_iter = _events.begin();
1410 if (_events.empty()) { // 0 events
1412 } else if (_events.end() == ++length_check_iter) { // 1 event
1413 return rt_safe_earliest_event_discrete_unlocked (start, x, y, inclusive);
1416 // Hack to avoid infinitely repeating the same event
1417 build_search_cache_if_necessary (start);
1419 if (_search_cache.first != _events.end()) {
1421 const ControlEvent* first = NULL;
1422 const ControlEvent* next = NULL;
1424 if (_search_cache.first == _events.begin() || (*_search_cache.first)->when <= start) {
1425 /* Step is after first */
1426 first = *_search_cache.first;
1427 ++_search_cache.first;
1428 if (_search_cache.first == _events.end()) {
1431 next = *_search_cache.first;
1434 /* Step is before first */
1435 const_iterator prev = _search_cache.first;
1438 next = *_search_cache.first;
1441 if (inclusive && first->when == start) {
1444 /* Move left of cache to this point
1445 * (Optimize for immediate call this cycle within range) */
1446 _search_cache.left = x;
1448 } else if (next->when < start || (!inclusive && next->when == start)) {
1449 /* "Next" is before the start, no points left. */
1453 if (fabs(first->value - next->value) <= 1) {
1454 if (next->when > start) {
1457 /* Move left of cache to this point
1458 * (Optimize for immediate call this cycle within range) */
1459 _search_cache.left = x;
1466 const double slope = (next->value - first->value) / (double)(next->when - first->when);
1467 //cerr << "start y: " << start_y << endl;
1469 //y = first->value + (slope * fabs(start - first->when));
1472 if (first->value < next->value) // ramping up
1474 else // ramping down
1477 x = first->when + (y - first->value) / (double)slope;
1479 while ((inclusive && x < start) || (x <= start && y != next->value)) {
1481 if (first->value < next->value) // ramping up
1483 else // ramping down
1486 x = first->when + (y - first->value) / (double)slope;
1489 /*cerr << first->value << " @ " << first->when << " ... "
1490 << next->value << " @ " << next->when
1491 << " = " << y << " @ " << x << endl;*/
1493 assert( (y >= first->value && y <= next->value)
1494 || (y <= first->value && y >= next->value) );
1497 const bool past_start = (inclusive ? x >= start : x > start);
1499 /* Move left of cache to this point
1500 * (Optimize for immediate call this cycle within range) */
1501 _search_cache.left = x;
1502 assert(inclusive ? x >= start : x > start);
1510 _search_cache.left = x;
1515 /* No points in the future, so no steps (towards them) in the future */
1521 /** @param start Start position in model coordinates.
1522 * @param end End position in model coordinates.
1523 * @param op 0 = cut, 1 = copy, 2 = clear.
1525 boost::shared_ptr<ControlList>
1526 ControlList::cut_copy_clear (double start, double end, int op)
1528 boost::shared_ptr<ControlList> nal = create (_parameter, _desc);
1530 ControlEvent cp (start, 0.0);
1533 Glib::Threads::RWLock::WriterLock lm (_lock);
1535 /* first, determine s & e, two iterators that define the range of points
1536 affected by this operation
1539 if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) == _events.end()) {
1543 /* and the last that is at or after `end' */
1545 e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1548 /* if "start" isn't the location of an existing point,
1549 evaluate the curve to get a value for the start. Add a point to
1550 both the existing event list, and if its not a "clear" operation,
1551 to the copy ("nal") as well.
1553 Note that the time positions of the points in each list are different
1554 because we want the copy ("nal") to have a zero time reference.
1558 /* before we begin any cut/clear operations, get the value of the curve
1562 double end_value = unlocked_eval (end);
1564 if ((*s)->when != start) {
1566 double val = unlocked_eval (start);
1568 if (op == 0) { // cut
1569 if (start > _events.front()->when) {
1570 _events.insert (s, (new ControlEvent (start, val)));
1574 if (op != 2) { // ! clear
1575 nal->_events.push_back (new ControlEvent (0, val));
1579 for (iterator x = s; x != e; ) {
1581 /* adjust new points to be relative to start, which
1582 has been set to zero.
1586 nal->_events.push_back (new ControlEvent ((*x)->when - start, (*x)->value));
1590 x = _events.erase (x);
1596 if (e == _events.end() || (*e)->when != end) {
1598 /* only add a boundary point if there is a point after "end"
1601 if (op == 0 && (e != _events.end() && end < (*e)->when)) { // cut
1602 _events.insert (e, new ControlEvent (end, end_value));
1605 if (op != 2 && (e != _events.end() && end < (*e)->when)) { // cut/copy
1606 nal->_events.push_back (new ControlEvent (end - start, end_value));
1610 unlocked_invalidate_insert_iterator ();
1615 maybe_signal_changed ();
1622 boost::shared_ptr<ControlList>
1623 ControlList::cut (double start, double end)
1625 return cut_copy_clear (start, end, 0);
1628 boost::shared_ptr<ControlList>
1629 ControlList::copy (double start, double end)
1631 return cut_copy_clear (start, end, 1);
1635 ControlList::clear (double start, double end)
1637 cut_copy_clear (start, end, 2);
1640 /** @param pos Position in model coordinates */
1642 ControlList::paste (const ControlList& alist, double pos, float /*times*/)
1644 if (alist._events.empty()) {
1649 Glib::Threads::RWLock::WriterLock lm (_lock);
1653 ControlEvent cp (pos, 0.0);
1655 where = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1657 for (const_iterator i = alist.begin();i != alist.end(); ++i) {
1658 double value = (*i)->value;
1659 if (alist.parameter() != parameter()) {
1660 const ParameterDescriptor& src_desc = alist.descriptor();
1662 value -= src_desc.lower; // translate to 0-relative
1663 value /= (src_desc.upper - src_desc.lower); // normalize range
1664 value *= (_desc.upper - _desc.lower); // scale to our range
1665 value += _desc.lower; // translate to our offset
1667 _events.insert (where, new ControlEvent((*i)->when + pos, value));
1668 end = (*i)->when + pos;
1672 /* move all points after the insertion along the timeline by
1676 while (where != _events.end()) {
1678 if ((*where)->when <= end) {
1681 _events.erase(where);
1689 unlocked_invalidate_insert_iterator ();
1693 maybe_signal_changed ();
1697 /** Move automation around according to a list of region movements.
1698 * @param return true if anything was changed, otherwise false (ie nothing needed changing)
1701 ControlList::move_ranges (const list< RangeMove<double> >& movements)
1703 typedef list< RangeMove<double> > RangeMoveList;
1706 Glib::Threads::RWLock::WriterLock lm (_lock);
1708 /* a copy of the events list before we started moving stuff around */
1709 EventList old_events = _events;
1711 /* clear the source and destination ranges in the new list */
1712 bool things_erased = false;
1713 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1715 if (erase_range_internal (i->from, i->from + i->length, _events)) {
1716 things_erased = true;
1719 if (erase_range_internal (i->to, i->to + i->length, _events)) {
1720 things_erased = true;
1724 /* if nothing was erased, there is nothing to do */
1725 if (!things_erased) {
1729 /* copy the events into the new list */
1730 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1731 iterator j = old_events.begin ();
1732 const double limit = i->from + i->length;
1733 const double dx = i->to - i->from;
1734 while (j != old_events.end () && (*j)->when <= limit) {
1735 if ((*j)->when >= i->from) {
1736 ControlEvent* ev = new ControlEvent (**j);
1738 _events.push_back (ev);
1745 _events.sort (event_time_less_than);
1746 unlocked_invalidate_insert_iterator ();
1748 _sort_pending = true;
1754 maybe_signal_changed ();
1759 ControlList::set_interpolation (InterpolationStyle s)
1761 if (_interpolation == s) {
1766 InterpolationChanged (s); /* EMIT SIGNAL */
1770 ControlList::operator!= (ControlList const & other) const
1772 if (_events.size() != other._events.size()) {
1776 EventList::const_iterator i = _events.begin ();
1777 EventList::const_iterator j = other._events.begin ();
1779 while (i != _events.end() && (*i)->when == (*j)->when && (*i)->value == (*j)->value) {
1784 if (i != _events.end ()) {
1789 _parameter != other._parameter ||
1790 _interpolation != other._interpolation ||
1791 _min_yval != other._min_yval ||
1792 _max_yval != other._max_yval ||
1793 _default_value != other._default_value
1798 ControlList::dump (ostream& o)
1800 /* NOT LOCKED ... for debugging only */
1802 for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
1803 o << (*x)->value << " @ " << (uint64_t) (*x)->when << endl;
1807 } // namespace Evoral