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 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, value));
468 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added value %2 at zero\n", this, 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));
477 add_guard_point (when);
482 maybe_signal_changed ();
487 ControlList::maybe_add_insert_guard (double when)
489 if (most_recent_insert_iterator != _events.end()) {
490 if ((*most_recent_insert_iterator)->when - when > 64) {
491 /* Next control point is some distance from where our new point is
492 going to go, so add a new point to avoid changing the shape of
493 the line too much. The insert iterator needs to point to the
494 new control point so that our insert will happen correctly. */
495 most_recent_insert_iterator = _events.insert (
496 most_recent_insert_iterator,
497 new ControlEvent (when + 64, (*most_recent_insert_iterator)->value));
498 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added insert guard point @ %2 = %3\n",
500 (*most_recent_insert_iterator)->value));
505 /** If we would just be adding to a straight line, move the previous point instead. */
507 ControlList::maybe_insert_straight_line (double when, double value)
509 if (_events.empty()) {
513 if (_events.back()->value == value) {
514 // Point b at the final point, which we know exists
515 EventList::iterator b = _events.end();
517 if (b == _events.begin()) {
518 return false; // No previous point
521 // Check the previous point's value
523 if ((*b)->value == value) {
524 /* At least two points with the exact same value (straight
525 line), just move the final point to the new time. */
526 _events.back()->when = when;
527 DEBUG_TRACE (DEBUG::ControlList, string_compose ("final value of %1 moved to %2\n", value, when));
534 ControlList::iterator
535 ControlList::erase_from_iterator_to (iterator iter, double when)
537 while (iter != _events.end()) {
538 if ((*iter)->when < when) {
539 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 erase existing @ %2\n", this, (*iter)->when));
541 iter = _events.erase (iter);
543 } else if ((*iter)->when >= when) {
552 ControlList::add (double when, double value, bool with_guards, bool with_initial)
554 /* this is for making changes from some kind of user interface or
555 control surface (GUI, MIDI, OSC etc)
558 DEBUG_TRACE (DEBUG::ControlList,
559 string_compose ("@%1 add %2 at %3 guards = %4 write pass = %5 (new? %6) at end? %7\n",
560 this, value, when, with_guards, _in_write_pass, new_write_pass,
561 (most_recent_insert_iterator == _events.end())));
563 Glib::Threads::RWLock::WriterLock lm (_lock);
564 ControlEvent cp (when, 0.0f);
565 iterator insertion_point;
567 if (_events.empty() && with_initial) {
569 /* empty: add an "anchor" point if the point we're adding past time 0 */
572 _events.insert (_events.end(), new ControlEvent (0, value));
573 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _default_value));
577 if (_in_write_pass && new_write_pass) {
579 /* first write in a write pass: add guard point if requested */
582 add_guard_point (insert_position);
583 did_write_during_pass = true;
585 /* not adding a guard, but we need to set iterator appropriately */
586 const ControlEvent cp (when, 0.0);
587 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
589 new_write_pass = false;
591 } else if (_in_write_pass &&
592 (most_recent_insert_iterator == _events.end() || when > (*most_recent_insert_iterator)->when)) {
594 /* in write pass: erase from most recent insert to now */
596 if (most_recent_insert_iterator != _events.end()) {
597 /* advance to avoid deleting the last inserted point itself. */
598 ++most_recent_insert_iterator;
601 most_recent_insert_iterator = erase_from_iterator_to(most_recent_insert_iterator, when);
603 maybe_add_insert_guard (when);
606 } else if (!_in_write_pass) {
608 /* not in a write pass: figure out the iterator we should insert in front of */
610 DEBUG_TRACE (DEBUG::ControlList, string_compose ("compute(b) MRI for position %1\n", when));
611 ControlEvent cp (when, 0.0f);
612 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
615 /* OK, now we're really ready to add a new point */
617 if (most_recent_insert_iterator == _events.end()) {
618 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 appending new point at end\n", this));
620 const bool done = maybe_insert_straight_line (when, value);
622 _events.push_back (new ControlEvent (when, value));
623 DEBUG_TRACE (DEBUG::ControlList, string_compose ("\tactually appended, size now %1\n", _events.size()));
626 most_recent_insert_iterator = _events.end();
627 --most_recent_insert_iterator;
629 } else if ((*most_recent_insert_iterator)->when == when) {
631 if ((*most_recent_insert_iterator)->value != value) {
632 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 reset existing point to new value %2\n", this, value));
634 /* only one point allowed per time point, so add a guard point
635 * before it if needed then reset the value of the point.
638 (*most_recent_insert_iterator)->value = value;
640 /* if we modified the final value, then its as
641 * if we inserted a new point as far as the
642 * next addition, so make sure we know that.
645 if (_events.back()->when == when) {
646 most_recent_insert_iterator = _events.end();
650 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 same time %2, same value value %3\n", this, when, value));
654 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert new point at %2 at iterator at %3\n", this, when, (*most_recent_insert_iterator)->when));
656 /* check for possible straight line here until maybe_insert_straight_line () handles the insert iterator properly*/
657 if (most_recent_insert_iterator != _events.begin ()) {
658 bool have_point2 = false;
659 --most_recent_insert_iterator;
660 const bool have_point1 = (*most_recent_insert_iterator)->value == value;
662 if (most_recent_insert_iterator != _events.begin ()) {
663 --most_recent_insert_iterator;
664 have_point2 = (*most_recent_insert_iterator)->value == value;
665 ++most_recent_insert_iterator;
668 if (have_point1 && have_point2) {
669 (*most_recent_insert_iterator)->when = when;
672 ++most_recent_insert_iterator;
675 //done = maybe_insert_straight_line (when, value) || done;
676 /* if the transport is stopped, add guard points (?) */
677 if (!done && !_in_write_pass && when > 64) {
678 add_guard_point (when - 64);
679 maybe_add_insert_guard (when);
683 maybe_add_insert_guard (when);
687 EventList::iterator x = _events.insert (most_recent_insert_iterator, new ControlEvent (when, value));
688 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 inserted new value before MRI, size now %2\n", this, _events.size()));
689 most_recent_insert_iterator = x;
696 maybe_signal_changed ();
700 ControlList::erase (iterator i)
703 Glib::Threads::RWLock::WriterLock lm (_lock);
704 if (most_recent_insert_iterator == i) {
705 unlocked_invalidate_insert_iterator ();
710 maybe_signal_changed ();
714 ControlList::erase (iterator start, iterator end)
717 Glib::Threads::RWLock::WriterLock lm (_lock);
718 _events.erase (start, end);
719 unlocked_invalidate_insert_iterator ();
722 maybe_signal_changed ();
725 /** Erase the first event which matches the given time and value */
727 ControlList::erase (double when, double value)
730 Glib::Threads::RWLock::WriterLock lm (_lock);
732 iterator i = begin ();
733 while (i != end() && ((*i)->when != when || (*i)->value != value)) {
739 if (most_recent_insert_iterator == i) {
740 unlocked_invalidate_insert_iterator ();
747 maybe_signal_changed ();
751 ControlList::erase_range (double start, double endt)
756 Glib::Threads::RWLock::WriterLock lm (_lock);
757 erased = erase_range_internal (start, endt, _events);
766 maybe_signal_changed ();
771 ControlList::erase_range_internal (double start, double endt, EventList & events)
774 ControlEvent cp (start, 0.0f);
778 if ((s = lower_bound (events.begin(), events.end(), &cp, time_comparator)) != events.end()) {
780 e = upper_bound (events.begin(), events.end(), &cp, time_comparator);
783 unlocked_invalidate_insert_iterator ();
792 ControlList::slide (iterator before, double distance)
795 Glib::Threads::RWLock::WriterLock lm (_lock);
797 if (before == _events.end()) {
801 while (before != _events.end()) {
802 (*before)->when += distance;
809 maybe_signal_changed ();
813 ControlList::shift (double pos, double frames)
816 Glib::Threads::RWLock::WriterLock lm (_lock);
818 for (iterator i = _events.begin(); i != _events.end(); ++i) {
819 if ((*i)->when >= pos) {
820 (*i)->when += frames;
827 maybe_signal_changed ();
831 ControlList::modify (iterator iter, double when, double val)
833 /* note: we assume higher level logic is in place to avoid this
834 reordering the time-order of control events in the list. ie. all
835 points after *iter are later than when.
839 Glib::Threads::RWLock::WriterLock lm (_lock);
841 (*iter)->when = when;
842 (*iter)->value = val;
843 if (isnan_local (val)) {
848 _events.sort (event_time_less_than);
849 unlocked_invalidate_insert_iterator ();
851 _sort_pending = true;
857 maybe_signal_changed ();
860 std::pair<ControlList::iterator,ControlList::iterator>
861 ControlList::control_points_adjacent (double xval)
863 Glib::Threads::RWLock::ReaderLock lm (_lock);
865 ControlEvent cp (xval, 0.0f);
866 std::pair<iterator,iterator> ret;
868 ret.first = _events.end();
869 ret.second = _events.end();
871 for (i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator); i != _events.end(); ++i) {
873 if (ret.first == _events.end()) {
874 if ((*i)->when >= xval) {
875 if (i != _events.begin()) {
884 if ((*i)->when > xval) {
894 ControlList::freeze ()
909 Glib::Threads::RWLock::WriterLock lm (_lock);
912 _events.sort (event_time_less_than);
913 unlocked_invalidate_insert_iterator ();
914 _sort_pending = false;
920 ControlList::mark_dirty () const
922 _lookup_cache.left = -1;
923 _lookup_cache.range.first = _events.end();
924 _lookup_cache.range.second = _events.end();
925 _search_cache.left = -1;
926 _search_cache.first = _events.end();
929 _curve->mark_dirty();
932 Dirty (); /* EMIT SIGNAL */
936 ControlList::truncate_end (double last_coordinate)
939 Glib::Threads::RWLock::WriterLock lm (_lock);
940 ControlEvent cp (last_coordinate, 0);
941 ControlList::reverse_iterator i;
944 if (_events.empty()) {
948 if (last_coordinate == _events.back()->when) {
952 if (last_coordinate > _events.back()->when) {
957 iterator foo = _events.begin();
960 if (foo == _events.end()) {
962 } else if (++foo == _events.end()) {
969 /* less than 2 points: add a new point */
970 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
973 /* more than 2 points: check to see if the last 2 values
974 are equal. if so, just move the position of the
975 last point. otherwise, add a new point.
978 iterator penultimate = _events.end();
979 --penultimate; /* points at last point */
980 --penultimate; /* points at the penultimate point */
982 if (_events.back()->value == (*penultimate)->value) {
983 _events.back()->when = last_coordinate;
985 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
993 last_val = unlocked_eval (last_coordinate);
994 last_val = max ((double) _min_yval, last_val);
995 last_val = min ((double) _max_yval, last_val);
997 i = _events.rbegin();
999 /* make i point to the last control point */
1003 /* now go backwards, removing control points that are
1004 beyond the new last coordinate.
1007 // FIXME: SLOW! (size() == O(n))
1009 uint32_t sz = _events.size();
1011 while (i != _events.rend() && sz > 2) {
1012 ControlList::reverse_iterator tmp;
1017 if ((*i)->when < last_coordinate) {
1021 _events.erase (i.base());
1027 _events.back()->when = last_coordinate;
1028 _events.back()->value = last_val;
1031 unlocked_invalidate_insert_iterator ();
1035 maybe_signal_changed ();
1039 ControlList::truncate_start (double overall_length)
1042 Glib::Threads::RWLock::WriterLock lm (_lock);
1044 double first_legal_value;
1045 double first_legal_coordinate;
1047 if (_events.empty()) {
1048 /* nothing to truncate */
1050 } else if (overall_length == _events.back()->when) {
1051 /* no change in overall length */
1055 if (overall_length > _events.back()->when) {
1057 /* growing at front: duplicate first point. shift all others */
1059 double shift = overall_length - _events.back()->when;
1062 for (np = 0, i = _events.begin(); i != _events.end(); ++i, ++np) {
1063 (*i)->when += shift;
1068 /* less than 2 points: add a new point */
1069 _events.push_front (new ControlEvent (0, _events.front()->value));
1073 /* more than 2 points: check to see if the first 2 values
1074 are equal. if so, just move the position of the
1075 first point. otherwise, add a new point.
1078 iterator second = _events.begin();
1079 ++second; /* points at the second point */
1081 if (_events.front()->value == (*second)->value) {
1082 /* first segment is flat, just move start point back to zero */
1083 _events.front()->when = 0;
1085 /* leave non-flat segment in place, add a new leading point. */
1086 _events.push_front (new ControlEvent (0, _events.front()->value));
1092 /* shrinking at front */
1094 first_legal_coordinate = _events.back()->when - overall_length;
1095 first_legal_value = unlocked_eval (first_legal_coordinate);
1096 first_legal_value = max (_min_yval, first_legal_value);
1097 first_legal_value = min (_max_yval, first_legal_value);
1099 /* remove all events earlier than the new "front" */
1101 i = _events.begin();
1103 while (i != _events.end() && !_events.empty()) {
1104 ControlList::iterator tmp;
1109 if ((*i)->when > first_legal_coordinate) {
1119 /* shift all remaining points left to keep their same
1123 for (i = _events.begin(); i != _events.end(); ++i) {
1124 (*i)->when -= first_legal_coordinate;
1127 /* add a new point for the interpolated new value */
1129 _events.push_front (new ControlEvent (0, first_legal_value));
1132 unlocked_invalidate_insert_iterator ();
1136 maybe_signal_changed ();
1140 ControlList::unlocked_eval (double x) const
1142 pair<EventList::iterator,EventList::iterator> range;
1148 const_iterator length_check_iter = _events.begin();
1149 for (npoints = 0; npoints < 4; ++npoints, ++length_check_iter) {
1150 if (length_check_iter == _events.end()) {
1157 return _default_value;
1160 return _events.front()->value;
1163 if (x >= _events.back()->when) {
1164 return _events.back()->value;
1165 } else if (x <= _events.front()->when) {
1166 return _events.front()->value;
1169 lpos = _events.front()->when;
1170 lval = _events.front()->value;
1171 upos = _events.back()->when;
1172 uval = _events.back()->value;
1174 if (_interpolation == Discrete) {
1178 /* linear interpolation betweeen the two points */
1179 fraction = (double) (x - lpos) / (double) (upos - lpos);
1180 return lval + (fraction * (uval - lval));
1183 if (x >= _events.back()->when) {
1184 return _events.back()->value;
1185 } else if (x <= _events.front()->when) {
1186 return _events.front()->value;
1189 return multipoint_eval (x);
1192 abort(); /*NOTREACHED*/ /* stupid gcc */
1193 return _default_value;
1197 ControlList::multipoint_eval (double x) const
1203 /* "Stepped" lookup (no interpolation) */
1204 /* FIXME: no cache. significant? */
1205 if (_interpolation == Discrete) {
1206 const ControlEvent cp (x, 0);
1207 EventList::const_iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
1209 // shouldn't have made it to multipoint_eval
1210 assert(i != _events.end());
1212 if (i == _events.begin() || (*i)->when == x)
1215 return (*(--i))->value;
1218 /* Only do the range lookup if x is in a different range than last time
1219 * this was called (or if the lookup cache has been marked "dirty" (left<0) */
1220 if ((_lookup_cache.left < 0) ||
1221 ((_lookup_cache.left > x) ||
1222 (_lookup_cache.range.first == _events.end()) ||
1223 ((*_lookup_cache.range.second)->when < x))) {
1225 const ControlEvent cp (x, 0);
1227 _lookup_cache.range = equal_range (_events.begin(), _events.end(), &cp, time_comparator);
1230 pair<const_iterator,const_iterator> range = _lookup_cache.range;
1232 if (range.first == range.second) {
1234 /* x does not exist within the list as a control point */
1236 _lookup_cache.left = x;
1238 if (range.first != _events.begin()) {
1240 lpos = (*range.first)->when;
1241 lval = (*range.first)->value;
1243 /* we're before the first point */
1244 // return _default_value;
1245 return _events.front()->value;
1248 if (range.second == _events.end()) {
1249 /* we're after the last point */
1250 return _events.back()->value;
1253 upos = (*range.second)->when;
1254 uval = (*range.second)->value;
1256 /* linear interpolation betweeen the two points
1260 fraction = (double) (x - lpos) / (double) (upos - lpos);
1261 return lval + (fraction * (uval - lval));
1265 /* x is a control point in the data */
1266 _lookup_cache.left = -1;
1267 return (*range.first)->value;
1271 ControlList::build_search_cache_if_necessary (double start) const
1273 if (_events.empty()) {
1274 /* Empty, nothing to cache, move to end. */
1275 _search_cache.first = _events.end();
1276 _search_cache.left = 0;
1278 } else if ((_search_cache.left < 0) || (_search_cache.left > start)) {
1279 /* Marked dirty (left < 0), or we're too far forward, re-search. */
1281 const ControlEvent start_point (start, 0);
1283 _search_cache.first = lower_bound (_events.begin(), _events.end(), &start_point, time_comparator);
1284 _search_cache.left = start;
1287 /* We now have a search cache that is not too far right, but it may be too
1288 far left and need to be advanced. */
1290 while (_search_cache.first != end() && (*_search_cache.first)->when < start) {
1291 ++_search_cache.first;
1293 _search_cache.left = start;
1296 /** Get the earliest event after \a start using the current interpolation style.
1298 * If an event is found, \a x and \a y are set to its coordinates.
1300 * \param inclusive Include events with timestamp exactly equal to \a start
1301 * \return true if event is found (and \a x and \a y are valid).
1304 ControlList::rt_safe_earliest_event (double start, double& x, double& y, bool inclusive) const
1306 // FIXME: It would be nice if this was unnecessary..
1307 Glib::Threads::RWLock::ReaderLock lm(_lock, Glib::Threads::TRY_LOCK);
1312 return rt_safe_earliest_event_unlocked (start, x, y, inclusive);
1316 /** Get the earliest event after \a start using the current interpolation style.
1318 * If an event is found, \a x and \a y are set to its coordinates.
1320 * \param inclusive Include events with timestamp exactly equal to \a start
1321 * \return true if event is found (and \a x and \a y are valid).
1324 ControlList::rt_safe_earliest_event_unlocked (double start, double& x, double& y, bool inclusive) const
1326 if (_interpolation == Discrete) {
1327 return rt_safe_earliest_event_discrete_unlocked(start, x, y, inclusive);
1329 return rt_safe_earliest_event_linear_unlocked(start, x, y, inclusive);
1334 /** Get the earliest event after \a start without interpolation.
1336 * If an event is found, \a x and \a y are set to its coordinates.
1338 * \param inclusive Include events with timestamp exactly equal to \a start
1339 * \return true if event is found (and \a x and \a y are valid).
1342 ControlList::rt_safe_earliest_event_discrete_unlocked (double start, double& x, double& y, bool inclusive) const
1344 build_search_cache_if_necessary (start);
1346 if (_search_cache.first != _events.end()) {
1347 const ControlEvent* const first = *_search_cache.first;
1349 const bool past_start = (inclusive ? first->when >= start : first->when > start);
1351 /* Earliest points is in range, return it */
1357 /* Move left of cache to this point
1358 * (Optimize for immediate call this cycle within range) */
1359 _search_cache.left = x;
1360 ++_search_cache.first;
1369 /* No points in range */
1375 /** Get the earliest time the line crosses an integer (Linear interpolation).
1377 * If an event is found, \a x and \a y are set to its coordinates.
1379 * \param inclusive Include events with timestamp exactly equal to \a start
1380 * \return true if event is found (and \a x and \a y are valid).
1383 ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, double& y, bool inclusive) const
1385 // cout << "earliest_event(start: " << start << ", x: " << x << ", y: " << y << ", inclusive: " << inclusive << ")" << endl;
1387 const_iterator length_check_iter = _events.begin();
1388 if (_events.empty()) { // 0 events
1390 } else if (_events.end() == ++length_check_iter) { // 1 event
1391 return rt_safe_earliest_event_discrete_unlocked (start, x, y, inclusive);
1394 // Hack to avoid infinitely repeating the same event
1395 build_search_cache_if_necessary (start);
1397 if (_search_cache.first != _events.end()) {
1399 const ControlEvent* first = NULL;
1400 const ControlEvent* next = NULL;
1402 if (_search_cache.first == _events.begin() || (*_search_cache.first)->when <= start) {
1403 /* Step is after first */
1404 first = *_search_cache.first;
1405 ++_search_cache.first;
1406 if (_search_cache.first == _events.end()) {
1409 next = *_search_cache.first;
1412 /* Step is before first */
1413 const_iterator prev = _search_cache.first;
1416 next = *_search_cache.first;
1419 if (inclusive && first->when == start) {
1422 /* Move left of cache to this point
1423 * (Optimize for immediate call this cycle within range) */
1424 _search_cache.left = x;
1426 } else if (next->when < start || (!inclusive && next->when == start)) {
1427 /* "Next" is before the start, no points left. */
1431 if (fabs(first->value - next->value) <= 1) {
1432 if (next->when > start) {
1435 /* Move left of cache to this point
1436 * (Optimize for immediate call this cycle within range) */
1437 _search_cache.left = x;
1444 const double slope = (next->value - first->value) / (double)(next->when - first->when);
1445 //cerr << "start y: " << start_y << endl;
1447 //y = first->value + (slope * fabs(start - first->when));
1450 if (first->value < next->value) // ramping up
1452 else // ramping down
1455 x = first->when + (y - first->value) / (double)slope;
1457 while ((inclusive && x < start) || (x <= start && y != next->value)) {
1459 if (first->value < next->value) // ramping up
1461 else // ramping down
1464 x = first->when + (y - first->value) / (double)slope;
1467 /*cerr << first->value << " @ " << first->when << " ... "
1468 << next->value << " @ " << next->when
1469 << " = " << y << " @ " << x << endl;*/
1471 assert( (y >= first->value && y <= next->value)
1472 || (y <= first->value && y >= next->value) );
1475 const bool past_start = (inclusive ? x >= start : x > start);
1477 /* Move left of cache to this point
1478 * (Optimize for immediate call this cycle within range) */
1479 _search_cache.left = x;
1480 assert(inclusive ? x >= start : x > start);
1488 _search_cache.left = x;
1493 /* No points in the future, so no steps (towards them) in the future */
1499 /** @param start Start position in model coordinates.
1500 * @param end End position in model coordinates.
1501 * @param op 0 = cut, 1 = copy, 2 = clear.
1503 boost::shared_ptr<ControlList>
1504 ControlList::cut_copy_clear (double start, double end, int op)
1506 boost::shared_ptr<ControlList> nal = create (_parameter, _desc);
1508 ControlEvent cp (start, 0.0);
1511 Glib::Threads::RWLock::WriterLock lm (_lock);
1513 /* first, determine s & e, two iterators that define the range of points
1514 affected by this operation
1517 if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) == _events.end()) {
1521 /* and the last that is at or after `end' */
1523 e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1526 /* if "start" isn't the location of an existing point,
1527 evaluate the curve to get a value for the start. Add a point to
1528 both the existing event list, and if its not a "clear" operation,
1529 to the copy ("nal") as well.
1531 Note that the time positions of the points in each list are different
1532 because we want the copy ("nal") to have a zero time reference.
1536 /* before we begin any cut/clear operations, get the value of the curve
1540 double end_value = unlocked_eval (end);
1542 if ((*s)->when != start) {
1544 double val = unlocked_eval (start);
1546 if (op == 0) { // cut
1547 if (start > _events.front()->when) {
1548 _events.insert (s, (new ControlEvent (start, val)));
1552 if (op != 2) { // ! clear
1553 nal->_events.push_back (new ControlEvent (0, val));
1557 for (iterator x = s; x != e; ) {
1559 /* adjust new points to be relative to start, which
1560 has been set to zero.
1564 nal->_events.push_back (new ControlEvent ((*x)->when - start, (*x)->value));
1568 x = _events.erase (x);
1574 if (e == _events.end() || (*e)->when != end) {
1576 /* only add a boundary point if there is a point after "end"
1579 if (op == 0 && (e != _events.end() && end < (*e)->when)) { // cut
1580 _events.insert (e, new ControlEvent (end, end_value));
1583 if (op != 2 && (e != _events.end() && end < (*e)->when)) { // cut/copy
1584 nal->_events.push_back (new ControlEvent (end - start, end_value));
1588 unlocked_invalidate_insert_iterator ();
1593 maybe_signal_changed ();
1600 boost::shared_ptr<ControlList>
1601 ControlList::cut (double start, double end)
1603 return cut_copy_clear (start, end, 0);
1606 boost::shared_ptr<ControlList>
1607 ControlList::copy (double start, double end)
1609 return cut_copy_clear (start, end, 1);
1613 ControlList::clear (double start, double end)
1615 cut_copy_clear (start, end, 2);
1618 /** @param pos Position in model coordinates */
1620 ControlList::paste (const ControlList& alist, double pos, float /*times*/)
1622 if (alist._events.empty()) {
1627 Glib::Threads::RWLock::WriterLock lm (_lock);
1631 ControlEvent cp (pos, 0.0);
1633 where = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1635 for (const_iterator i = alist.begin();i != alist.end(); ++i) {
1636 double value = (*i)->value;
1637 if (alist.parameter() != parameter()) {
1638 const ParameterDescriptor& src_desc = alist.descriptor();
1640 value -= src_desc.lower; // translate to 0-relative
1641 value /= (src_desc.upper - src_desc.lower); // normalize range
1642 value *= (_desc.upper - _desc.lower); // scale to our range
1643 value += _desc.lower; // translate to our offset
1645 _events.insert (where, new ControlEvent((*i)->when + pos, value));
1646 end = (*i)->when + pos;
1650 /* move all points after the insertion along the timeline by
1654 while (where != _events.end()) {
1656 if ((*where)->when <= end) {
1659 _events.erase(where);
1667 unlocked_invalidate_insert_iterator ();
1671 maybe_signal_changed ();
1675 /** Move automation around according to a list of region movements.
1676 * @param return true if anything was changed, otherwise false (ie nothing needed changing)
1679 ControlList::move_ranges (const list< RangeMove<double> >& movements)
1681 typedef list< RangeMove<double> > RangeMoveList;
1684 Glib::Threads::RWLock::WriterLock lm (_lock);
1686 /* a copy of the events list before we started moving stuff around */
1687 EventList old_events = _events;
1689 /* clear the source and destination ranges in the new list */
1690 bool things_erased = false;
1691 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1693 if (erase_range_internal (i->from, i->from + i->length, _events)) {
1694 things_erased = true;
1697 if (erase_range_internal (i->to, i->to + i->length, _events)) {
1698 things_erased = true;
1702 /* if nothing was erased, there is nothing to do */
1703 if (!things_erased) {
1707 /* copy the events into the new list */
1708 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1709 iterator j = old_events.begin ();
1710 const double limit = i->from + i->length;
1711 const double dx = i->to - i->from;
1712 while (j != old_events.end () && (*j)->when <= limit) {
1713 if ((*j)->when >= i->from) {
1714 ControlEvent* ev = new ControlEvent (**j);
1716 _events.push_back (ev);
1723 _events.sort (event_time_less_than);
1724 unlocked_invalidate_insert_iterator ();
1726 _sort_pending = true;
1732 maybe_signal_changed ();
1737 ControlList::set_interpolation (InterpolationStyle s)
1739 if (_interpolation == s) {
1744 InterpolationChanged (s); /* EMIT SIGNAL */
1748 ControlList::operator!= (ControlList const & other) const
1750 if (_events.size() != other._events.size()) {
1754 EventList::const_iterator i = _events.begin ();
1755 EventList::const_iterator j = other._events.begin ();
1757 while (i != _events.end() && (*i)->when == (*j)->when && (*i)->value == (*j)->value) {
1762 if (i != _events.end ()) {
1767 _parameter != other._parameter ||
1768 _interpolation != other._interpolation ||
1769 _min_yval != other._min_yval ||
1770 _max_yval != other._max_yval ||
1771 _default_value != other._default_value
1776 ControlList::dump (ostream& o)
1778 /* NOT LOCKED ... for debugging only */
1780 for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
1781 o << (*x)->value << " @ " << (uint64_t) (*x)->when << endl;
1785 } // namespace Evoral