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) {
147 boost::shared_ptr<ControlList>
148 ControlList::create(const Parameter& id, const ParameterDescriptor& desc)
150 return boost::shared_ptr<ControlList>(new ControlList(id, desc));
154 ControlList::operator== (const ControlList& other)
156 return _events == other._events;
160 ControlList::operator= (const ControlList& other)
162 if (this != &other) {
164 _min_yval = other._min_yval;
165 _max_yval = other._max_yval;
168 _interpolation = other._interpolation;
169 _default_value = other._default_value;
178 ControlList::copy_events (const ControlList& other)
181 Glib::Threads::RWLock::WriterLock lm (_lock);
182 for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
186 for (const_iterator i = other.begin(); i != other.end(); ++i) {
187 _events.push_back (new ControlEvent ((*i)->when, (*i)->value));
189 unlocked_invalidate_insert_iterator ();
192 maybe_signal_changed ();
196 ControlList::create_curve()
198 _curve = new Curve(*this);
202 ControlList::destroy_curve()
209 ControlList::maybe_signal_changed ()
214 _changed_when_thawed = true;
219 ControlList::clear ()
222 Glib::Threads::RWLock::WriterLock lm (_lock);
223 for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
227 unlocked_invalidate_insert_iterator ();
231 maybe_signal_changed ();
235 ControlList::x_scale (double factor)
237 Glib::Threads::RWLock::WriterLock lm (_lock);
242 ControlList::extend_to (double when)
244 Glib::Threads::RWLock::WriterLock lm (_lock);
245 if (_events.empty() || _events.back()->when == when) {
248 double factor = when / _events.back()->when;
254 ControlList::y_transform (boost::function<double(double)> callback)
257 Glib::Threads::RWLock::WriterLock lm (_lock);
258 for (iterator i = _events.begin(); i != _events.end(); ++i) {
259 (*i)->value = callback ((*i)->value);
263 maybe_signal_changed ();
267 ControlList::list_merge (ControlList const& other, boost::function<double(double, double)> callback)
270 Glib::Threads::RWLock::WriterLock lm (_lock);
272 /* First scale existing events, copy into a new list.
273 * The original list is needed later to interpolate
274 * for new events only present in the master list.
276 for (iterator i = _events.begin(); i != _events.end(); ++i) {
277 float val = callback ((*i)->value, other.eval ((*i)->when));
278 nel.push_back (new ControlEvent ((*i)->when , val));
280 /* Now add events which are only present in the master-list. */
281 const EventList& evl (other.events());
282 for (const_iterator i = evl.begin(); i != evl.end(); ++i) {
284 // TODO: optimize, remember last matching iterator (lists are sorted)
285 for (iterator j = _events.begin(); j != _events.end(); ++j) {
286 if ((*i)->when == (*j)->when) {
291 /* skip events that have already been merge in the first pass */
295 float val = callback (unlocked_eval ((*i)->when), (*i)->value);
296 nel.push_back (new ControlEvent ((*i)->when, val));
298 nel.sort (event_time_less_than);
300 for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
306 unlocked_invalidate_insert_iterator ();
309 maybe_signal_changed ();
313 ControlList::_x_scale (double factor)
315 for (iterator i = _events.begin(); i != _events.end(); ++i) {
316 (*i)->when *= factor;
322 struct ControlEventTimeComparator {
323 bool operator() (ControlEvent* a, ControlEvent* b) {
324 return a->when < b->when;
329 ControlList::thin (double thinning_factor)
331 if (thinning_factor == 0.0 || _desc.toggled) {
335 bool changed = false;
338 Glib::Threads::RWLock::WriterLock lm (_lock);
340 ControlEvent* prevprev = 0;
341 ControlEvent* cur = 0;
342 ControlEvent* prev = 0;
346 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 thin from %2 events\n", this, _events.size()));
348 for (iterator i = _events.begin(); i != _events.end(); ++i) {
355 /* compute the area of the triangle formed by 3 points
358 double area = fabs ((prevprev->when * (prev->value - cur->value)) +
359 (prev->when * (cur->value - prevprev->value)) +
360 (cur->when * (prevprev->value - prev->value)));
362 if (area < thinning_factor) {
363 iterator tmp = pprev;
365 /* pprev will change to current
366 i is incremented to the next event
382 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 thin => %2 events\n", this, _events.size()));
385 unlocked_invalidate_insert_iterator ();
391 maybe_signal_changed ();
396 ControlList::fast_simple_add (double when, double value)
398 Glib::Threads::RWLock::WriterLock lm (_lock);
399 /* to be used only for loading pre-sorted data from saved state */
400 _events.insert (_events.end(), new ControlEvent (when, value));
406 ControlList::invalidate_insert_iterator ()
408 Glib::Threads::RWLock::WriterLock lm (_lock);
409 unlocked_invalidate_insert_iterator ();
413 ControlList::unlocked_invalidate_insert_iterator ()
415 most_recent_insert_iterator = _events.end();
419 ControlList::start_write_pass (double when)
421 Glib::Threads::RWLock::WriterLock lm (_lock);
423 DEBUG_TRACE (DEBUG::ControlList, string_compose ("%1: setup write pass @ %2\n", this, when));
425 new_write_pass = true;
426 did_write_during_pass = false;
427 insert_position = when;
429 /* leave the insert iterator invalid, so that we will do the lookup
430 of where it should be in a "lazy" way - deferring it until
431 we actually add the first point (which may never happen).
434 unlocked_invalidate_insert_iterator ();
438 ControlList::write_pass_finished (double /*when*/, double thinning_factor)
440 DEBUG_TRACE (DEBUG::ControlList, "write pass finished\n");
442 if (did_write_during_pass) {
443 thin (thinning_factor);
444 did_write_during_pass = false;
446 new_write_pass = true;
447 _in_write_pass = false;
451 ControlList::set_in_write_pass (bool yn, bool add_point, double when)
453 DEBUG_TRACE (DEBUG::ControlList, string_compose ("now in write pass @ %1, add point ? %2\n", when, add_point));
457 if (yn && add_point) {
458 add_guard_point (when);
463 ControlList::add_guard_point (double when)
465 ControlEvent cp (when, 0.0);
466 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
468 double eval_value = unlocked_eval (insert_position);
470 if (most_recent_insert_iterator == _events.end()) {
472 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert iterator at end, adding eval-value there %2\n", this, eval_value));
473 _events.push_back (new ControlEvent (when, eval_value));
474 /* leave insert iterator at the end */
476 } else if ((*most_recent_insert_iterator)->when == when) {
478 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert iterator at existing point, setting eval-value there %2\n", this, eval_value));
480 /* most_recent_insert_iterator points to a control event
481 already at the insert position, so there is
486 advance most_recent_insert_iterator so that the "real"
487 insert occurs in the right place, since it
488 points to the control event just inserted.
491 ++most_recent_insert_iterator;
494 /* insert a new control event at the right spot
497 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert eval-value %2 just before iterator @ %3\n",
498 this, eval_value, (*most_recent_insert_iterator)->when));
500 most_recent_insert_iterator = _events.insert (most_recent_insert_iterator, new ControlEvent (when, eval_value));
502 /* advance most_recent_insert_iterator so that the "real"
503 * insert occurs in the right place, since it
504 * points to the control event just inserted.
507 ++most_recent_insert_iterator;
510 /* don't do this again till the next write pass */
512 new_write_pass = false;
516 ControlList::in_write_pass () const
518 return _in_write_pass;
522 ControlList::editor_add (double when, double value, bool with_guard)
524 /* this is for making changes from a graphical line editor
527 ControlEvent cp (when, 0.0f);
528 iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
530 if (i != _events.end () && (*i)->when == when) {
534 if (_events.empty()) {
536 /* as long as the point we're adding is not at zero,
537 * add an "anchor" point there.
541 _events.insert (_events.end(), new ControlEvent (0, value));
542 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added value %2 at zero\n", this, value));
546 insert_position = when;
549 add_guard_point (when - 64);
551 maybe_add_insert_guard (when);
554 /* clamp new value to allowed range */
556 value = max (_min_yval, value);
557 value = min (_max_yval, value);
560 DEBUG_TRACE (DEBUG::ControlList, string_compose ("editor_add: actually add when= %1 value= %2\n", when, value));
561 result = _events.insert (i, new ControlEvent (when, value));
568 maybe_signal_changed ();
574 ControlList::maybe_add_insert_guard (double when)
576 if (most_recent_insert_iterator != _events.end()) {
577 if ((*most_recent_insert_iterator)->when - when > 64) {
578 /* Next control point is some distance from where our new point is
579 going to go, so add a new point to avoid changing the shape of
580 the line too much. The insert iterator needs to point to the
581 new control point so that our insert will happen correctly. */
582 most_recent_insert_iterator = _events.insert (
583 most_recent_insert_iterator,
584 new ControlEvent (when + 64, (*most_recent_insert_iterator)->value));
585 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added insert guard point @ %2 = %3\n",
587 (*most_recent_insert_iterator)->value));
592 /** If we would just be adding to a straight line, move the previous point instead. */
594 ControlList::maybe_insert_straight_line (double when, double value)
596 if (_events.empty()) {
600 if (_events.back()->value == value) {
601 // Point b at the final point, which we know exists
602 EventList::iterator b = _events.end();
604 if (b == _events.begin()) {
605 return false; // No previous point
608 // Check the previous point's value
610 if ((*b)->value == value) {
611 /* At least two points with the exact same value (straight
612 line), just move the final point to the new time. */
613 _events.back()->when = when;
614 DEBUG_TRACE (DEBUG::ControlList, string_compose ("final value of %1 moved to %2\n", value, when));
621 ControlList::iterator
622 ControlList::erase_from_iterator_to (iterator iter, double when)
624 while (iter != _events.end()) {
625 if ((*iter)->when < when) {
626 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 erase existing @ %2\n", this, (*iter)->when));
628 iter = _events.erase (iter);
630 } else if ((*iter)->when >= when) {
639 ControlList::add (double when, double value, bool with_guards, bool with_initial)
641 /* this is for making changes from some kind of user interface or
642 control surface (GUI, MIDI, OSC etc)
645 DEBUG_TRACE (DEBUG::ControlList,
646 string_compose ("@%1 add %2 at %3 guards = %4 write pass = %5 (new? %6) at end? %7\n",
647 this, value, when, with_guards, _in_write_pass, new_write_pass,
648 (most_recent_insert_iterator == _events.end())));
650 Glib::Threads::RWLock::WriterLock lm (_lock);
651 ControlEvent cp (when, 0.0f);
652 iterator insertion_point;
654 if (_events.empty() && with_initial) {
656 /* empty: add an "anchor" point if the point we're adding past time 0 */
660 const double opp_val = ((value < 0.5) ? 1.0 : 0.0);
661 _events.insert (_events.end(), new ControlEvent (0, opp_val));
662 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added toggled value %2 at zero\n", this, opp_val));
665 _events.insert (_events.end(), new ControlEvent (0, value));
666 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _default_value));
671 if (_in_write_pass && new_write_pass) {
673 /* first write in a write pass: add guard point if requested */
676 add_guard_point (insert_position);
677 did_write_during_pass = true;
679 /* not adding a guard, but we need to set iterator appropriately */
680 const ControlEvent cp (when, 0.0);
681 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
683 new_write_pass = false;
685 } else if (_in_write_pass &&
686 (most_recent_insert_iterator == _events.end() || when > (*most_recent_insert_iterator)->when)) {
688 /* in write pass: erase from most recent insert to now */
690 if (most_recent_insert_iterator != _events.end()) {
691 /* advance to avoid deleting the last inserted point itself. */
692 ++most_recent_insert_iterator;
695 most_recent_insert_iterator = erase_from_iterator_to(most_recent_insert_iterator, when);
697 maybe_add_insert_guard (when);
700 } else if (!_in_write_pass) {
702 /* not in a write pass: figure out the iterator we should insert in front of */
704 DEBUG_TRACE (DEBUG::ControlList, string_compose ("compute(b) MRI for position %1\n", when));
705 ControlEvent cp (when, 0.0f);
706 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
709 /* OK, now we're really ready to add a new point */
711 if (most_recent_insert_iterator == _events.end()) {
712 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 appending new point at end\n", this));
714 const bool done = maybe_insert_straight_line (when, value);
716 _events.push_back (new ControlEvent (when, value));
717 DEBUG_TRACE (DEBUG::ControlList, string_compose ("\tactually appended, size now %1\n", _events.size()));
720 most_recent_insert_iterator = _events.end();
721 --most_recent_insert_iterator;
723 } else if ((*most_recent_insert_iterator)->when == when) {
725 if ((*most_recent_insert_iterator)->value != value) {
726 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 reset existing point to new value %2\n", this, value));
728 /* only one point allowed per time point, so add a guard point
729 * before it if needed then reset the value of the point.
732 (*most_recent_insert_iterator)->value = value;
734 /* if we modified the final value, then its as
735 * if we inserted a new point as far as the
736 * next addition, so make sure we know that.
739 if (_events.back()->when == when) {
740 most_recent_insert_iterator = _events.end();
744 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 same time %2, same value value %3\n", this, when, value));
748 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert new point at %2 at iterator at %3\n", this, when, (*most_recent_insert_iterator)->when));
750 /* check for possible straight line here until maybe_insert_straight_line () handles the insert iterator properly*/
751 if (most_recent_insert_iterator != _events.begin ()) {
752 bool have_point2 = false;
753 --most_recent_insert_iterator;
754 const bool have_point1 = (*most_recent_insert_iterator)->value == value;
756 if (most_recent_insert_iterator != _events.begin ()) {
757 --most_recent_insert_iterator;
758 have_point2 = (*most_recent_insert_iterator)->value == value;
759 ++most_recent_insert_iterator;
762 if (have_point1 && have_point2) {
763 (*most_recent_insert_iterator)->when = when;
766 ++most_recent_insert_iterator;
769 //done = maybe_insert_straight_line (when, value) || done;
770 /* if the transport is stopped, add guard points (?) */
771 if (!done && !_in_write_pass && when > 64) {
772 add_guard_point (when - 64);
773 maybe_add_insert_guard (when);
777 maybe_add_insert_guard (when);
781 EventList::iterator x = _events.insert (most_recent_insert_iterator, new ControlEvent (when, value));
782 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 inserted new value before MRI, size now %2\n", this, _events.size()));
783 most_recent_insert_iterator = x;
790 maybe_signal_changed ();
794 ControlList::erase (iterator i)
797 Glib::Threads::RWLock::WriterLock lm (_lock);
798 if (most_recent_insert_iterator == i) {
799 unlocked_invalidate_insert_iterator ();
804 maybe_signal_changed ();
808 ControlList::erase (iterator start, iterator end)
811 Glib::Threads::RWLock::WriterLock lm (_lock);
812 _events.erase (start, end);
813 unlocked_invalidate_insert_iterator ();
816 maybe_signal_changed ();
819 /** Erase the first event which matches the given time and value */
821 ControlList::erase (double when, double value)
824 Glib::Threads::RWLock::WriterLock lm (_lock);
826 iterator i = begin ();
827 while (i != end() && ((*i)->when != when || (*i)->value != value)) {
833 if (most_recent_insert_iterator == i) {
834 unlocked_invalidate_insert_iterator ();
841 maybe_signal_changed ();
845 ControlList::erase_range (double start, double endt)
850 Glib::Threads::RWLock::WriterLock lm (_lock);
851 erased = erase_range_internal (start, endt, _events);
860 maybe_signal_changed ();
865 ControlList::erase_range_internal (double start, double endt, EventList & events)
868 ControlEvent cp (start, 0.0f);
872 if ((s = lower_bound (events.begin(), events.end(), &cp, time_comparator)) != events.end()) {
874 e = upper_bound (events.begin(), events.end(), &cp, time_comparator);
877 unlocked_invalidate_insert_iterator ();
886 ControlList::slide (iterator before, double distance)
889 Glib::Threads::RWLock::WriterLock lm (_lock);
891 if (before == _events.end()) {
895 while (before != _events.end()) {
896 (*before)->when += distance;
903 maybe_signal_changed ();
907 ControlList::shift (double pos, double frames)
910 Glib::Threads::RWLock::WriterLock lm (_lock);
912 for (iterator i = _events.begin(); i != _events.end(); ++i) {
913 if ((*i)->when >= pos) {
914 (*i)->when += frames;
921 maybe_signal_changed ();
925 ControlList::modify (iterator iter, double when, double val)
927 /* note: we assume higher level logic is in place to avoid this
928 reordering the time-order of control events in the list. ie. all
929 points after *iter are later than when.
933 Glib::Threads::RWLock::WriterLock lm (_lock);
935 (*iter)->when = when;
936 (*iter)->value = val;
937 if (isnan_local (val)) {
942 _events.sort (event_time_less_than);
943 unlocked_invalidate_insert_iterator ();
945 _sort_pending = true;
951 maybe_signal_changed ();
954 std::pair<ControlList::iterator,ControlList::iterator>
955 ControlList::control_points_adjacent (double xval)
957 Glib::Threads::RWLock::ReaderLock lm (_lock);
959 ControlEvent cp (xval, 0.0f);
960 std::pair<iterator,iterator> ret;
962 ret.first = _events.end();
963 ret.second = _events.end();
965 for (i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator); i != _events.end(); ++i) {
967 if (ret.first == _events.end()) {
968 if ((*i)->when >= xval) {
969 if (i != _events.begin()) {
978 if ((*i)->when > xval) {
988 ControlList::freeze ()
1003 Glib::Threads::RWLock::WriterLock lm (_lock);
1005 if (_sort_pending) {
1006 _events.sort (event_time_less_than);
1007 unlocked_invalidate_insert_iterator ();
1008 _sort_pending = false;
1014 ControlList::mark_dirty () const
1016 _lookup_cache.left = -1;
1017 _lookup_cache.range.first = _events.end();
1018 _lookup_cache.range.second = _events.end();
1019 _search_cache.left = -1;
1020 _search_cache.first = _events.end();
1023 _curve->mark_dirty();
1026 Dirty (); /* EMIT SIGNAL */
1030 ControlList::truncate_end (double last_coordinate)
1033 Glib::Threads::RWLock::WriterLock lm (_lock);
1034 ControlEvent cp (last_coordinate, 0);
1035 ControlList::reverse_iterator i;
1038 if (_events.empty()) {
1042 if (last_coordinate == _events.back()->when) {
1046 if (last_coordinate > _events.back()->when) {
1051 iterator foo = _events.begin();
1054 if (foo == _events.end()) {
1056 } else if (++foo == _events.end()) {
1059 lessthantwo = false;
1063 /* less than 2 points: add a new point */
1064 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
1067 /* more than 2 points: check to see if the last 2 values
1068 are equal. if so, just move the position of the
1069 last point. otherwise, add a new point.
1072 iterator penultimate = _events.end();
1073 --penultimate; /* points at last point */
1074 --penultimate; /* points at the penultimate point */
1076 if (_events.back()->value == (*penultimate)->value) {
1077 _events.back()->when = last_coordinate;
1079 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
1085 /* shortening end */
1087 last_val = unlocked_eval (last_coordinate);
1088 last_val = max ((double) _min_yval, last_val);
1089 last_val = min ((double) _max_yval, last_val);
1091 i = _events.rbegin();
1093 /* make i point to the last control point */
1097 /* now go backwards, removing control points that are
1098 beyond the new last coordinate.
1101 // FIXME: SLOW! (size() == O(n))
1103 uint32_t sz = _events.size();
1105 while (i != _events.rend() && sz > 2) {
1106 ControlList::reverse_iterator tmp;
1111 if ((*i)->when < last_coordinate) {
1115 _events.erase (i.base());
1121 _events.back()->when = last_coordinate;
1122 _events.back()->value = last_val;
1125 unlocked_invalidate_insert_iterator ();
1129 maybe_signal_changed ();
1133 ControlList::truncate_start (double overall_length)
1136 Glib::Threads::RWLock::WriterLock lm (_lock);
1138 double first_legal_value;
1139 double first_legal_coordinate;
1141 if (_events.empty()) {
1142 /* nothing to truncate */
1144 } else if (overall_length == _events.back()->when) {
1145 /* no change in overall length */
1149 if (overall_length > _events.back()->when) {
1151 /* growing at front: duplicate first point. shift all others */
1153 double shift = overall_length - _events.back()->when;
1156 for (np = 0, i = _events.begin(); i != _events.end(); ++i, ++np) {
1157 (*i)->when += shift;
1162 /* less than 2 points: add a new point */
1163 _events.push_front (new ControlEvent (0, _events.front()->value));
1167 /* more than 2 points: check to see if the first 2 values
1168 are equal. if so, just move the position of the
1169 first point. otherwise, add a new point.
1172 iterator second = _events.begin();
1173 ++second; /* points at the second point */
1175 if (_events.front()->value == (*second)->value) {
1176 /* first segment is flat, just move start point back to zero */
1177 _events.front()->when = 0;
1179 /* leave non-flat segment in place, add a new leading point. */
1180 _events.push_front (new ControlEvent (0, _events.front()->value));
1186 /* shrinking at front */
1188 first_legal_coordinate = _events.back()->when - overall_length;
1189 first_legal_value = unlocked_eval (first_legal_coordinate);
1190 first_legal_value = max (_min_yval, first_legal_value);
1191 first_legal_value = min (_max_yval, first_legal_value);
1193 /* remove all events earlier than the new "front" */
1195 i = _events.begin();
1197 while (i != _events.end() && !_events.empty()) {
1198 ControlList::iterator tmp;
1203 if ((*i)->when > first_legal_coordinate) {
1213 /* shift all remaining points left to keep their same
1217 for (i = _events.begin(); i != _events.end(); ++i) {
1218 (*i)->when -= first_legal_coordinate;
1221 /* add a new point for the interpolated new value */
1223 _events.push_front (new ControlEvent (0, first_legal_value));
1226 unlocked_invalidate_insert_iterator ();
1230 maybe_signal_changed ();
1234 ControlList::unlocked_eval (double x) const
1236 pair<EventList::iterator,EventList::iterator> range;
1242 const_iterator length_check_iter = _events.begin();
1243 for (npoints = 0; npoints < 4; ++npoints, ++length_check_iter) {
1244 if (length_check_iter == _events.end()) {
1251 return _default_value;
1254 return _events.front()->value;
1257 if (x >= _events.back()->when) {
1258 return _events.back()->value;
1259 } else if (x <= _events.front()->when) {
1260 return _events.front()->value;
1263 lpos = _events.front()->when;
1264 lval = _events.front()->value;
1265 upos = _events.back()->when;
1266 uval = _events.back()->value;
1268 if (_interpolation == Discrete) {
1272 /* linear interpolation between the two points */
1273 fraction = (double) (x - lpos) / (double) (upos - lpos);
1274 return lval + (fraction * (uval - lval));
1277 if (x >= _events.back()->when) {
1278 return _events.back()->value;
1279 } else if (x <= _events.front()->when) {
1280 return _events.front()->value;
1283 return multipoint_eval (x);
1286 abort(); /*NOTREACHED*/ /* stupid gcc */
1287 return _default_value;
1291 ControlList::multipoint_eval (double x) const
1297 /* "Stepped" lookup (no interpolation) */
1298 /* FIXME: no cache. significant? */
1299 if (_interpolation == Discrete) {
1300 const ControlEvent cp (x, 0);
1301 EventList::const_iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
1303 // shouldn't have made it to multipoint_eval
1304 assert(i != _events.end());
1306 if (i == _events.begin() || (*i)->when == x)
1309 return (*(--i))->value;
1312 /* Only do the range lookup if x is in a different range than last time
1313 * this was called (or if the lookup cache has been marked "dirty" (left<0) */
1314 if ((_lookup_cache.left < 0) ||
1315 ((_lookup_cache.left > x) ||
1316 (_lookup_cache.range.first == _events.end()) ||
1317 ((*_lookup_cache.range.second)->when < x))) {
1319 const ControlEvent cp (x, 0);
1321 _lookup_cache.range = equal_range (_events.begin(), _events.end(), &cp, time_comparator);
1324 pair<const_iterator,const_iterator> range = _lookup_cache.range;
1326 if (range.first == range.second) {
1328 /* x does not exist within the list as a control point */
1330 _lookup_cache.left = x;
1332 if (range.first != _events.begin()) {
1334 lpos = (*range.first)->when;
1335 lval = (*range.first)->value;
1337 /* we're before the first point */
1338 // return _default_value;
1339 return _events.front()->value;
1342 if (range.second == _events.end()) {
1343 /* we're after the last point */
1344 return _events.back()->value;
1347 upos = (*range.second)->when;
1348 uval = (*range.second)->value;
1350 /* linear interpolation betweeen the two points
1354 fraction = (double) (x - lpos) / (double) (upos - lpos);
1355 return lval + (fraction * (uval - lval));
1359 /* x is a control point in the data */
1360 _lookup_cache.left = -1;
1361 return (*range.first)->value;
1365 ControlList::build_search_cache_if_necessary (double start) const
1367 if (_events.empty()) {
1368 /* Empty, nothing to cache, move to end. */
1369 _search_cache.first = _events.end();
1370 _search_cache.left = 0;
1372 } else if ((_search_cache.left < 0) || (_search_cache.left > start)) {
1373 /* Marked dirty (left < 0), or we're too far forward, re-search. */
1375 const ControlEvent start_point (start, 0);
1377 _search_cache.first = lower_bound (_events.begin(), _events.end(), &start_point, time_comparator);
1378 _search_cache.left = start;
1381 /* We now have a search cache that is not too far right, but it may be too
1382 far left and need to be advanced. */
1384 while (_search_cache.first != end() && (*_search_cache.first)->when < start) {
1385 ++_search_cache.first;
1387 _search_cache.left = start;
1390 /** Get the earliest event after \a start using the current interpolation style.
1392 * If an event is found, \a x and \a y are set to its coordinates.
1394 * \param inclusive Include events with timestamp exactly equal to \a start
1395 * \return true if event is found (and \a x and \a y are valid).
1398 ControlList::rt_safe_earliest_event (double start, double& x, double& y, bool inclusive) const
1400 // FIXME: It would be nice if this was unnecessary..
1401 Glib::Threads::RWLock::ReaderLock lm(_lock, Glib::Threads::TRY_LOCK);
1406 return rt_safe_earliest_event_unlocked (start, x, y, inclusive);
1410 /** Get the earliest event after \a start using the current interpolation style.
1412 * If an event is found, \a x and \a y are set to its coordinates.
1414 * \param inclusive Include events with timestamp exactly equal to \a start
1415 * \return true if event is found (and \a x and \a y are valid).
1418 ControlList::rt_safe_earliest_event_unlocked (double start, double& x, double& y, bool inclusive) const
1420 if (_interpolation == Discrete) {
1421 return rt_safe_earliest_event_discrete_unlocked(start, x, y, inclusive);
1423 return rt_safe_earliest_event_linear_unlocked(start, x, y, inclusive);
1428 /** Get the earliest event after \a start without interpolation.
1430 * If an event is found, \a x and \a y are set to its coordinates.
1432 * \param inclusive Include events with timestamp exactly equal to \a start
1433 * \return true if event is found (and \a x and \a y are valid).
1436 ControlList::rt_safe_earliest_event_discrete_unlocked (double start, double& x, double& y, bool inclusive) const
1438 build_search_cache_if_necessary (start);
1440 if (_search_cache.first != _events.end()) {
1441 const ControlEvent* const first = *_search_cache.first;
1443 const bool past_start = (inclusive ? first->when >= start : first->when > start);
1445 /* Earliest points is in range, return it */
1451 /* Move left of cache to this point
1452 * (Optimize for immediate call this cycle within range) */
1453 _search_cache.left = x;
1454 ++_search_cache.first;
1463 /* No points in range */
1469 /** Get the earliest time the line crosses an integer (Linear interpolation).
1471 * If an event is found, \a x and \a y are set to its coordinates.
1473 * \param inclusive Include events with timestamp exactly equal to \a start
1474 * \return true if event is found (and \a x and \a y are valid).
1477 ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, double& y, bool inclusive) const
1479 // cout << "earliest_event(start: " << start << ", x: " << x << ", y: " << y << ", inclusive: " << inclusive << ")" << endl;
1481 const_iterator length_check_iter = _events.begin();
1482 if (_events.empty()) { // 0 events
1484 } else if (_events.end() == ++length_check_iter) { // 1 event
1485 return rt_safe_earliest_event_discrete_unlocked (start, x, y, inclusive);
1488 // Hack to avoid infinitely repeating the same event
1489 build_search_cache_if_necessary (start);
1491 if (_search_cache.first != _events.end()) {
1493 const ControlEvent* first = NULL;
1494 const ControlEvent* next = NULL;
1496 if (_search_cache.first == _events.begin() || (*_search_cache.first)->when <= start) {
1497 /* Step is after first */
1498 first = *_search_cache.first;
1499 ++_search_cache.first;
1500 if (_search_cache.first == _events.end()) {
1503 next = *_search_cache.first;
1506 /* Step is before first */
1507 const_iterator prev = _search_cache.first;
1510 next = *_search_cache.first;
1513 if (inclusive && first->when == start) {
1516 /* Move left of cache to this point
1517 * (Optimize for immediate call this cycle within range) */
1518 _search_cache.left = x;
1520 } else if (next->when < start || (!inclusive && next->when == start)) {
1521 /* "Next" is before the start, no points left. */
1525 if (fabs(first->value - next->value) <= 1) {
1526 if (next->when > start) {
1529 /* Move left of cache to this point
1530 * (Optimize for immediate call this cycle within range) */
1531 _search_cache.left = x;
1538 const double slope = (next->value - first->value) / (double)(next->when - first->when);
1539 //cerr << "start y: " << start_y << endl;
1541 //y = first->value + (slope * fabs(start - first->when));
1544 if (first->value < next->value) // ramping up
1546 else // ramping down
1549 x = first->when + (y - first->value) / (double)slope;
1551 while ((inclusive && x < start) || (x <= start && y != next->value)) {
1553 if (first->value < next->value) // ramping up
1555 else // ramping down
1558 x = first->when + (y - first->value) / (double)slope;
1561 /*cerr << first->value << " @ " << first->when << " ... "
1562 << next->value << " @ " << next->when
1563 << " = " << y << " @ " << x << endl;*/
1565 assert( (y >= first->value && y <= next->value)
1566 || (y <= first->value && y >= next->value) );
1569 const bool past_start = (inclusive ? x >= start : x > start);
1571 /* Move left of cache to this point
1572 * (Optimize for immediate call this cycle within range) */
1573 _search_cache.left = x;
1574 assert(inclusive ? x >= start : x > start);
1582 _search_cache.left = x;
1587 /* No points in the future, so no steps (towards them) in the future */
1593 /** @param start Start position in model coordinates.
1594 * @param end End position in model coordinates.
1595 * @param op 0 = cut, 1 = copy, 2 = clear.
1597 boost::shared_ptr<ControlList>
1598 ControlList::cut_copy_clear (double start, double end, int op)
1600 boost::shared_ptr<ControlList> nal = create (_parameter, _desc);
1602 ControlEvent cp (start, 0.0);
1605 Glib::Threads::RWLock::WriterLock lm (_lock);
1607 /* first, determine s & e, two iterators that define the range of points
1608 affected by this operation
1611 if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) == _events.end()) {
1615 /* and the last that is at or after `end' */
1617 e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1620 /* if "start" isn't the location of an existing point,
1621 evaluate the curve to get a value for the start. Add a point to
1622 both the existing event list, and if its not a "clear" operation,
1623 to the copy ("nal") as well.
1625 Note that the time positions of the points in each list are different
1626 because we want the copy ("nal") to have a zero time reference.
1630 /* before we begin any cut/clear operations, get the value of the curve
1634 double end_value = unlocked_eval (end);
1636 if ((*s)->when != start) {
1638 double val = unlocked_eval (start);
1640 if (op == 0) { // cut
1641 if (start > _events.front()->when) {
1642 _events.insert (s, (new ControlEvent (start, val)));
1646 if (op != 2) { // ! clear
1647 nal->_events.push_back (new ControlEvent (0, val));
1651 for (iterator x = s; x != e; ) {
1653 /* adjust new points to be relative to start, which
1654 has been set to zero.
1658 nal->_events.push_back (new ControlEvent ((*x)->when - start, (*x)->value));
1662 x = _events.erase (x);
1668 if (e == _events.end() || (*e)->when != end) {
1670 /* only add a boundary point if there is a point after "end"
1673 if (op == 0 && (e != _events.end() && end < (*e)->when)) { // cut
1674 _events.insert (e, new ControlEvent (end, end_value));
1677 if (op != 2 && (e != _events.end() && end < (*e)->when)) { // cut/copy
1678 nal->_events.push_back (new ControlEvent (end - start, end_value));
1682 unlocked_invalidate_insert_iterator ();
1687 maybe_signal_changed ();
1694 boost::shared_ptr<ControlList>
1695 ControlList::cut (double start, double end)
1697 return cut_copy_clear (start, end, 0);
1700 boost::shared_ptr<ControlList>
1701 ControlList::copy (double start, double end)
1703 return cut_copy_clear (start, end, 1);
1707 ControlList::clear (double start, double end)
1709 cut_copy_clear (start, end, 2);
1712 /** @param pos Position in model coordinates */
1714 ControlList::paste (const ControlList& alist, double pos)
1716 if (alist._events.empty()) {
1721 Glib::Threads::RWLock::WriterLock lm (_lock);
1725 ControlEvent cp (pos, 0.0);
1727 where = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1729 for (const_iterator i = alist.begin();i != alist.end(); ++i) {
1730 double value = (*i)->value;
1731 if (alist.parameter() != parameter()) {
1732 const ParameterDescriptor& src_desc = alist.descriptor();
1734 // This does not work for logscale and will probably also not do
1735 // the right thing for integer_step and sr_dependent parameters.
1737 // TODO various flags from from ARDOUR::ParameterDescriptor
1738 // to Evoral::ParameterDescriptor
1740 value -= src_desc.lower; // translate to 0-relative
1741 value /= (src_desc.upper - src_desc.lower); // normalize range
1742 value *= (_desc.upper - _desc.lower); // scale to our range
1743 value += _desc.lower; // translate to our offset
1744 if (_desc.toggled) {
1745 value = (value < 0.5) ? 0.0 : 1.0;
1748 _events.insert (where, new ControlEvent((*i)->when + pos, value));
1749 end = (*i)->when + pos;
1753 /* move all points after the insertion along the timeline by
1757 while (where != _events.end()) {
1759 if ((*where)->when <= end) {
1762 _events.erase(where);
1770 unlocked_invalidate_insert_iterator ();
1774 maybe_signal_changed ();
1778 /** Move automation around according to a list of region movements.
1779 * @param return true if anything was changed, otherwise false (ie nothing needed changing)
1782 ControlList::move_ranges (const list< RangeMove<double> >& movements)
1784 typedef list< RangeMove<double> > RangeMoveList;
1787 Glib::Threads::RWLock::WriterLock lm (_lock);
1789 /* a copy of the events list before we started moving stuff around */
1790 EventList old_events = _events;
1792 /* clear the source and destination ranges in the new list */
1793 bool things_erased = false;
1794 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1796 if (erase_range_internal (i->from, i->from + i->length, _events)) {
1797 things_erased = true;
1800 if (erase_range_internal (i->to, i->to + i->length, _events)) {
1801 things_erased = true;
1805 /* if nothing was erased, there is nothing to do */
1806 if (!things_erased) {
1810 /* copy the events into the new list */
1811 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1812 iterator j = old_events.begin ();
1813 const double limit = i->from + i->length;
1814 const double dx = i->to - i->from;
1815 while (j != old_events.end () && (*j)->when <= limit) {
1816 if ((*j)->when >= i->from) {
1817 ControlEvent* ev = new ControlEvent (**j);
1819 _events.push_back (ev);
1826 _events.sort (event_time_less_than);
1827 unlocked_invalidate_insert_iterator ();
1829 _sort_pending = true;
1835 maybe_signal_changed ();
1840 ControlList::set_interpolation (InterpolationStyle s)
1842 if (_interpolation == s) {
1847 InterpolationChanged (s); /* EMIT SIGNAL */
1851 ControlList::operator!= (ControlList const & other) const
1853 if (_events.size() != other._events.size()) {
1857 EventList::const_iterator i = _events.begin ();
1858 EventList::const_iterator j = other._events.begin ();
1860 while (i != _events.end() && (*i)->when == (*j)->when && (*i)->value == (*j)->value) {
1865 if (i != _events.end ()) {
1870 _parameter != other._parameter ||
1871 _interpolation != other._interpolation ||
1872 _min_yval != other._min_yval ||
1873 _max_yval != other._max_yval ||
1874 _default_value != other._default_value
1879 ControlList::dump (ostream& o)
1881 /* NOT LOCKED ... for debugging only */
1883 for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
1884 o << (*x)->value << " @ " << (uint64_t) (*x)->when << endl;
1888 } // namespace Evoral