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 insert_position = when;
475 add_guard_point (when - 64);
477 maybe_add_insert_guard (when);
480 ControlEvent cp (when, 0.0f);
481 iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
482 DEBUG_TRACE (DEBUG::ControlList, string_compose ("editor_add: actually add when= %1 value= %2\n", when, value));
483 _events.insert (i, new ControlEvent (when, value));
487 maybe_signal_changed ();
492 ControlList::maybe_add_insert_guard (double when)
494 if (most_recent_insert_iterator != _events.end()) {
495 if ((*most_recent_insert_iterator)->when - when > 64) {
496 /* Next control point is some distance from where our new point is
497 going to go, so add a new point to avoid changing the shape of
498 the line too much. The insert iterator needs to point to the
499 new control point so that our insert will happen correctly. */
500 most_recent_insert_iterator = _events.insert (
501 most_recent_insert_iterator,
502 new ControlEvent (when + 64, (*most_recent_insert_iterator)->value));
503 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added insert guard point @ %2 = %3\n",
505 (*most_recent_insert_iterator)->value));
510 /** If we would just be adding to a straight line, move the previous point instead. */
512 ControlList::maybe_insert_straight_line (double when, double value)
514 if (_events.empty()) {
518 if (_events.back()->value == value) {
519 // Point b at the final point, which we know exists
520 EventList::iterator b = _events.end();
522 if (b == _events.begin()) {
523 return false; // No previous point
526 // Check the previous point's value
528 if ((*b)->value == value) {
529 /* At least two points with the exact same value (straight
530 line), just move the final point to the new time. */
531 _events.back()->when = when;
532 DEBUG_TRACE (DEBUG::ControlList, string_compose ("final value of %1 moved to %2\n", value, when));
539 ControlList::iterator
540 ControlList::erase_from_iterator_to (iterator iter, double when)
542 while (iter != _events.end()) {
543 if ((*iter)->when < when) {
544 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 erase existing @ %2\n", this, (*iter)->when));
546 iter = _events.erase (iter);
548 } else if ((*iter)->when >= when) {
557 ControlList::add (double when, double value, bool with_guards, bool with_initial)
559 /* this is for making changes from some kind of user interface or
560 control surface (GUI, MIDI, OSC etc)
563 DEBUG_TRACE (DEBUG::ControlList,
564 string_compose ("@%1 add %2 at %3 guards = %4 write pass = %5 (new? %6) at end? %7\n",
565 this, value, when, with_guards, _in_write_pass, new_write_pass,
566 (most_recent_insert_iterator == _events.end())));
568 Glib::Threads::RWLock::WriterLock lm (_lock);
569 ControlEvent cp (when, 0.0f);
570 iterator insertion_point;
572 if (_events.empty() && with_initial) {
574 /* empty: add an "anchor" point if the point we're adding past time 0 */
577 _events.insert (_events.end(), new ControlEvent (0, value));
578 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _default_value));
582 if (_in_write_pass && new_write_pass) {
584 /* first write in a write pass: add guard point if requested */
587 add_guard_point (insert_position);
588 did_write_during_pass = true;
590 /* not adding a guard, but we need to set iterator appropriately */
591 const ControlEvent cp (when, 0.0);
592 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
594 new_write_pass = false;
596 } else if (_in_write_pass &&
597 (most_recent_insert_iterator == _events.end() || when > (*most_recent_insert_iterator)->when)) {
599 /* in write pass: erase from most recent insert to now */
601 if (most_recent_insert_iterator != _events.end()) {
602 /* advance to avoid deleting the last inserted point itself. */
603 ++most_recent_insert_iterator;
606 most_recent_insert_iterator = erase_from_iterator_to(most_recent_insert_iterator, when);
608 maybe_add_insert_guard (when);
611 } else if (!_in_write_pass) {
613 /* not in a write pass: figure out the iterator we should insert in front of */
615 DEBUG_TRACE (DEBUG::ControlList, string_compose ("compute(b) MRI for position %1\n", when));
616 ControlEvent cp (when, 0.0f);
617 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
620 /* OK, now we're really ready to add a new point */
622 if (most_recent_insert_iterator == _events.end()) {
623 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 appending new point at end\n", this));
625 const bool done = maybe_insert_straight_line (when, value);
627 _events.push_back (new ControlEvent (when, value));
628 DEBUG_TRACE (DEBUG::ControlList, string_compose ("\tactually appended, size now %1\n", _events.size()));
631 most_recent_insert_iterator = _events.end();
632 --most_recent_insert_iterator;
634 } else if ((*most_recent_insert_iterator)->when == when) {
636 if ((*most_recent_insert_iterator)->value != value) {
637 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 reset existing point to new value %2\n", this, value));
639 /* only one point allowed per time point, so add a guard point
640 * before it if needed then reset the value of the point.
643 (*most_recent_insert_iterator)->value = value;
645 /* if we modified the final value, then its as
646 * if we inserted a new point as far as the
647 * next addition, so make sure we know that.
650 if (_events.back()->when == when) {
651 most_recent_insert_iterator = _events.end();
655 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 same time %2, same value value %3\n", this, when, value));
659 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert new point at %2 at iterator at %3\n", this, when, (*most_recent_insert_iterator)->when));
661 /* check for possible straight line here until maybe_insert_straight_line () handles the insert iterator properly*/
662 if (most_recent_insert_iterator != _events.begin ()) {
663 bool have_point2 = false;
664 --most_recent_insert_iterator;
665 const bool have_point1 = (*most_recent_insert_iterator)->value == value;
667 if (most_recent_insert_iterator != _events.begin ()) {
668 --most_recent_insert_iterator;
669 have_point2 = (*most_recent_insert_iterator)->value == value;
670 ++most_recent_insert_iterator;
673 if (have_point1 && have_point2) {
674 (*most_recent_insert_iterator)->when = when;
677 ++most_recent_insert_iterator;
680 //done = maybe_insert_straight_line (when, value) || done;
681 /* if the transport is stopped, add guard points (?) */
682 if (!done && !_in_write_pass && when > 64) {
683 add_guard_point (when - 64);
684 maybe_add_insert_guard (when);
688 maybe_add_insert_guard (when);
692 EventList::iterator x = _events.insert (most_recent_insert_iterator, new ControlEvent (when, value));
693 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 inserted new value before MRI, size now %2\n", this, _events.size()));
694 most_recent_insert_iterator = x;
701 maybe_signal_changed ();
705 ControlList::erase (iterator i)
708 Glib::Threads::RWLock::WriterLock lm (_lock);
709 if (most_recent_insert_iterator == i) {
710 unlocked_invalidate_insert_iterator ();
715 maybe_signal_changed ();
719 ControlList::erase (iterator start, iterator end)
722 Glib::Threads::RWLock::WriterLock lm (_lock);
723 _events.erase (start, end);
724 unlocked_invalidate_insert_iterator ();
727 maybe_signal_changed ();
730 /** Erase the first event which matches the given time and value */
732 ControlList::erase (double when, double value)
735 Glib::Threads::RWLock::WriterLock lm (_lock);
737 iterator i = begin ();
738 while (i != end() && ((*i)->when != when || (*i)->value != value)) {
744 if (most_recent_insert_iterator == i) {
745 unlocked_invalidate_insert_iterator ();
752 maybe_signal_changed ();
756 ControlList::erase_range (double start, double endt)
761 Glib::Threads::RWLock::WriterLock lm (_lock);
762 erased = erase_range_internal (start, endt, _events);
771 maybe_signal_changed ();
776 ControlList::erase_range_internal (double start, double endt, EventList & events)
779 ControlEvent cp (start, 0.0f);
783 if ((s = lower_bound (events.begin(), events.end(), &cp, time_comparator)) != events.end()) {
785 e = upper_bound (events.begin(), events.end(), &cp, time_comparator);
788 unlocked_invalidate_insert_iterator ();
797 ControlList::slide (iterator before, double distance)
800 Glib::Threads::RWLock::WriterLock lm (_lock);
802 if (before == _events.end()) {
806 while (before != _events.end()) {
807 (*before)->when += distance;
814 maybe_signal_changed ();
818 ControlList::shift (double pos, double frames)
821 Glib::Threads::RWLock::WriterLock lm (_lock);
823 for (iterator i = _events.begin(); i != _events.end(); ++i) {
824 if ((*i)->when >= pos) {
825 (*i)->when += frames;
832 maybe_signal_changed ();
836 ControlList::modify (iterator iter, double when, double val)
838 /* note: we assume higher level logic is in place to avoid this
839 reordering the time-order of control events in the list. ie. all
840 points after *iter are later than when.
844 Glib::Threads::RWLock::WriterLock lm (_lock);
846 (*iter)->when = when;
847 (*iter)->value = val;
848 if (isnan_local (val)) {
853 _events.sort (event_time_less_than);
854 unlocked_invalidate_insert_iterator ();
856 _sort_pending = true;
862 maybe_signal_changed ();
865 std::pair<ControlList::iterator,ControlList::iterator>
866 ControlList::control_points_adjacent (double xval)
868 Glib::Threads::RWLock::ReaderLock lm (_lock);
870 ControlEvent cp (xval, 0.0f);
871 std::pair<iterator,iterator> ret;
873 ret.first = _events.end();
874 ret.second = _events.end();
876 for (i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator); i != _events.end(); ++i) {
878 if (ret.first == _events.end()) {
879 if ((*i)->when >= xval) {
880 if (i != _events.begin()) {
889 if ((*i)->when > xval) {
899 ControlList::freeze ()
914 Glib::Threads::RWLock::WriterLock lm (_lock);
917 _events.sort (event_time_less_than);
918 unlocked_invalidate_insert_iterator ();
919 _sort_pending = false;
925 ControlList::mark_dirty () const
927 _lookup_cache.left = -1;
928 _lookup_cache.range.first = _events.end();
929 _lookup_cache.range.second = _events.end();
930 _search_cache.left = -1;
931 _search_cache.first = _events.end();
934 _curve->mark_dirty();
937 Dirty (); /* EMIT SIGNAL */
941 ControlList::truncate_end (double last_coordinate)
944 Glib::Threads::RWLock::WriterLock lm (_lock);
945 ControlEvent cp (last_coordinate, 0);
946 ControlList::reverse_iterator i;
949 if (_events.empty()) {
953 if (last_coordinate == _events.back()->when) {
957 if (last_coordinate > _events.back()->when) {
962 iterator foo = _events.begin();
965 if (foo == _events.end()) {
967 } else if (++foo == _events.end()) {
974 /* less than 2 points: add a new point */
975 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
978 /* more than 2 points: check to see if the last 2 values
979 are equal. if so, just move the position of the
980 last point. otherwise, add a new point.
983 iterator penultimate = _events.end();
984 --penultimate; /* points at last point */
985 --penultimate; /* points at the penultimate point */
987 if (_events.back()->value == (*penultimate)->value) {
988 _events.back()->when = last_coordinate;
990 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
998 last_val = unlocked_eval (last_coordinate);
999 last_val = max ((double) _min_yval, last_val);
1000 last_val = min ((double) _max_yval, last_val);
1002 i = _events.rbegin();
1004 /* make i point to the last control point */
1008 /* now go backwards, removing control points that are
1009 beyond the new last coordinate.
1012 // FIXME: SLOW! (size() == O(n))
1014 uint32_t sz = _events.size();
1016 while (i != _events.rend() && sz > 2) {
1017 ControlList::reverse_iterator tmp;
1022 if ((*i)->when < last_coordinate) {
1026 _events.erase (i.base());
1032 _events.back()->when = last_coordinate;
1033 _events.back()->value = last_val;
1036 unlocked_invalidate_insert_iterator ();
1040 maybe_signal_changed ();
1044 ControlList::truncate_start (double overall_length)
1047 Glib::Threads::RWLock::WriterLock lm (_lock);
1049 double first_legal_value;
1050 double first_legal_coordinate;
1052 if (_events.empty()) {
1053 /* nothing to truncate */
1055 } else if (overall_length == _events.back()->when) {
1056 /* no change in overall length */
1060 if (overall_length > _events.back()->when) {
1062 /* growing at front: duplicate first point. shift all others */
1064 double shift = overall_length - _events.back()->when;
1067 for (np = 0, i = _events.begin(); i != _events.end(); ++i, ++np) {
1068 (*i)->when += shift;
1073 /* less than 2 points: add a new point */
1074 _events.push_front (new ControlEvent (0, _events.front()->value));
1078 /* more than 2 points: check to see if the first 2 values
1079 are equal. if so, just move the position of the
1080 first point. otherwise, add a new point.
1083 iterator second = _events.begin();
1084 ++second; /* points at the second point */
1086 if (_events.front()->value == (*second)->value) {
1087 /* first segment is flat, just move start point back to zero */
1088 _events.front()->when = 0;
1090 /* leave non-flat segment in place, add a new leading point. */
1091 _events.push_front (new ControlEvent (0, _events.front()->value));
1097 /* shrinking at front */
1099 first_legal_coordinate = _events.back()->when - overall_length;
1100 first_legal_value = unlocked_eval (first_legal_coordinate);
1101 first_legal_value = max (_min_yval, first_legal_value);
1102 first_legal_value = min (_max_yval, first_legal_value);
1104 /* remove all events earlier than the new "front" */
1106 i = _events.begin();
1108 while (i != _events.end() && !_events.empty()) {
1109 ControlList::iterator tmp;
1114 if ((*i)->when > first_legal_coordinate) {
1124 /* shift all remaining points left to keep their same
1128 for (i = _events.begin(); i != _events.end(); ++i) {
1129 (*i)->when -= first_legal_coordinate;
1132 /* add a new point for the interpolated new value */
1134 _events.push_front (new ControlEvent (0, first_legal_value));
1137 unlocked_invalidate_insert_iterator ();
1141 maybe_signal_changed ();
1145 ControlList::unlocked_eval (double x) const
1147 pair<EventList::iterator,EventList::iterator> range;
1153 const_iterator length_check_iter = _events.begin();
1154 for (npoints = 0; npoints < 4; ++npoints, ++length_check_iter) {
1155 if (length_check_iter == _events.end()) {
1162 return _default_value;
1165 return _events.front()->value;
1168 if (x >= _events.back()->when) {
1169 return _events.back()->value;
1170 } else if (x <= _events.front()->when) {
1171 return _events.front()->value;
1174 lpos = _events.front()->when;
1175 lval = _events.front()->value;
1176 upos = _events.back()->when;
1177 uval = _events.back()->value;
1179 if (_interpolation == Discrete) {
1183 /* linear interpolation betweeen the two points */
1184 fraction = (double) (x - lpos) / (double) (upos - lpos);
1185 return lval + (fraction * (uval - lval));
1188 if (x >= _events.back()->when) {
1189 return _events.back()->value;
1190 } else if (x <= _events.front()->when) {
1191 return _events.front()->value;
1194 return multipoint_eval (x);
1197 abort(); /*NOTREACHED*/ /* stupid gcc */
1198 return _default_value;
1202 ControlList::multipoint_eval (double x) const
1208 /* "Stepped" lookup (no interpolation) */
1209 /* FIXME: no cache. significant? */
1210 if (_interpolation == Discrete) {
1211 const ControlEvent cp (x, 0);
1212 EventList::const_iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
1214 // shouldn't have made it to multipoint_eval
1215 assert(i != _events.end());
1217 if (i == _events.begin() || (*i)->when == x)
1220 return (*(--i))->value;
1223 /* Only do the range lookup if x is in a different range than last time
1224 * this was called (or if the lookup cache has been marked "dirty" (left<0) */
1225 if ((_lookup_cache.left < 0) ||
1226 ((_lookup_cache.left > x) ||
1227 (_lookup_cache.range.first == _events.end()) ||
1228 ((*_lookup_cache.range.second)->when < x))) {
1230 const ControlEvent cp (x, 0);
1232 _lookup_cache.range = equal_range (_events.begin(), _events.end(), &cp, time_comparator);
1235 pair<const_iterator,const_iterator> range = _lookup_cache.range;
1237 if (range.first == range.second) {
1239 /* x does not exist within the list as a control point */
1241 _lookup_cache.left = x;
1243 if (range.first != _events.begin()) {
1245 lpos = (*range.first)->when;
1246 lval = (*range.first)->value;
1248 /* we're before the first point */
1249 // return _default_value;
1250 return _events.front()->value;
1253 if (range.second == _events.end()) {
1254 /* we're after the last point */
1255 return _events.back()->value;
1258 upos = (*range.second)->when;
1259 uval = (*range.second)->value;
1261 /* linear interpolation betweeen the two points
1265 fraction = (double) (x - lpos) / (double) (upos - lpos);
1266 return lval + (fraction * (uval - lval));
1270 /* x is a control point in the data */
1271 _lookup_cache.left = -1;
1272 return (*range.first)->value;
1276 ControlList::build_search_cache_if_necessary (double start) const
1278 if (_events.empty()) {
1279 /* Empty, nothing to cache, move to end. */
1280 _search_cache.first = _events.end();
1281 _search_cache.left = 0;
1283 } else if ((_search_cache.left < 0) || (_search_cache.left > start)) {
1284 /* Marked dirty (left < 0), or we're too far forward, re-search. */
1286 const ControlEvent start_point (start, 0);
1288 _search_cache.first = lower_bound (_events.begin(), _events.end(), &start_point, time_comparator);
1289 _search_cache.left = start;
1292 /* We now have a search cache that is not too far right, but it may be too
1293 far left and need to be advanced. */
1295 while (_search_cache.first != end() && (*_search_cache.first)->when < start) {
1296 ++_search_cache.first;
1298 _search_cache.left = start;
1301 /** Get the earliest event after \a start using the current interpolation style.
1303 * If an event is found, \a x and \a y are set to its coordinates.
1305 * \param inclusive Include events with timestamp exactly equal to \a start
1306 * \return true if event is found (and \a x and \a y are valid).
1309 ControlList::rt_safe_earliest_event (double start, double& x, double& y, bool inclusive) const
1311 // FIXME: It would be nice if this was unnecessary..
1312 Glib::Threads::RWLock::ReaderLock lm(_lock, Glib::Threads::TRY_LOCK);
1317 return rt_safe_earliest_event_unlocked (start, x, y, inclusive);
1321 /** Get the earliest event after \a start using the current interpolation style.
1323 * If an event is found, \a x and \a y are set to its coordinates.
1325 * \param inclusive Include events with timestamp exactly equal to \a start
1326 * \return true if event is found (and \a x and \a y are valid).
1329 ControlList::rt_safe_earliest_event_unlocked (double start, double& x, double& y, bool inclusive) const
1331 if (_interpolation == Discrete) {
1332 return rt_safe_earliest_event_discrete_unlocked(start, x, y, inclusive);
1334 return rt_safe_earliest_event_linear_unlocked(start, x, y, inclusive);
1339 /** Get the earliest event after \a start without interpolation.
1341 * If an event is found, \a x and \a y are set to its coordinates.
1343 * \param inclusive Include events with timestamp exactly equal to \a start
1344 * \return true if event is found (and \a x and \a y are valid).
1347 ControlList::rt_safe_earliest_event_discrete_unlocked (double start, double& x, double& y, bool inclusive) const
1349 build_search_cache_if_necessary (start);
1351 if (_search_cache.first != _events.end()) {
1352 const ControlEvent* const first = *_search_cache.first;
1354 const bool past_start = (inclusive ? first->when >= start : first->when > start);
1356 /* Earliest points is in range, return it */
1362 /* Move left of cache to this point
1363 * (Optimize for immediate call this cycle within range) */
1364 _search_cache.left = x;
1365 ++_search_cache.first;
1374 /* No points in range */
1380 /** Get the earliest time the line crosses an integer (Linear interpolation).
1382 * If an event is found, \a x and \a y are set to its coordinates.
1384 * \param inclusive Include events with timestamp exactly equal to \a start
1385 * \return true if event is found (and \a x and \a y are valid).
1388 ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, double& y, bool inclusive) const
1390 // cout << "earliest_event(start: " << start << ", x: " << x << ", y: " << y << ", inclusive: " << inclusive << ")" << endl;
1392 const_iterator length_check_iter = _events.begin();
1393 if (_events.empty()) { // 0 events
1395 } else if (_events.end() == ++length_check_iter) { // 1 event
1396 return rt_safe_earliest_event_discrete_unlocked (start, x, y, inclusive);
1399 // Hack to avoid infinitely repeating the same event
1400 build_search_cache_if_necessary (start);
1402 if (_search_cache.first != _events.end()) {
1404 const ControlEvent* first = NULL;
1405 const ControlEvent* next = NULL;
1407 if (_search_cache.first == _events.begin() || (*_search_cache.first)->when <= start) {
1408 /* Step is after first */
1409 first = *_search_cache.first;
1410 ++_search_cache.first;
1411 if (_search_cache.first == _events.end()) {
1414 next = *_search_cache.first;
1417 /* Step is before first */
1418 const_iterator prev = _search_cache.first;
1421 next = *_search_cache.first;
1424 if (inclusive && first->when == start) {
1427 /* Move left of cache to this point
1428 * (Optimize for immediate call this cycle within range) */
1429 _search_cache.left = x;
1431 } else if (next->when < start || (!inclusive && next->when == start)) {
1432 /* "Next" is before the start, no points left. */
1436 if (fabs(first->value - next->value) <= 1) {
1437 if (next->when > start) {
1440 /* Move left of cache to this point
1441 * (Optimize for immediate call this cycle within range) */
1442 _search_cache.left = x;
1449 const double slope = (next->value - first->value) / (double)(next->when - first->when);
1450 //cerr << "start y: " << start_y << endl;
1452 //y = first->value + (slope * fabs(start - first->when));
1455 if (first->value < next->value) // ramping up
1457 else // ramping down
1460 x = first->when + (y - first->value) / (double)slope;
1462 while ((inclusive && x < start) || (x <= start && y != next->value)) {
1464 if (first->value < next->value) // ramping up
1466 else // ramping down
1469 x = first->when + (y - first->value) / (double)slope;
1472 /*cerr << first->value << " @ " << first->when << " ... "
1473 << next->value << " @ " << next->when
1474 << " = " << y << " @ " << x << endl;*/
1476 assert( (y >= first->value && y <= next->value)
1477 || (y <= first->value && y >= next->value) );
1480 const bool past_start = (inclusive ? x >= start : x > start);
1482 /* Move left of cache to this point
1483 * (Optimize for immediate call this cycle within range) */
1484 _search_cache.left = x;
1485 assert(inclusive ? x >= start : x > start);
1493 _search_cache.left = x;
1498 /* No points in the future, so no steps (towards them) in the future */
1504 /** @param start Start position in model coordinates.
1505 * @param end End position in model coordinates.
1506 * @param op 0 = cut, 1 = copy, 2 = clear.
1508 boost::shared_ptr<ControlList>
1509 ControlList::cut_copy_clear (double start, double end, int op)
1511 boost::shared_ptr<ControlList> nal = create (_parameter, _desc);
1513 ControlEvent cp (start, 0.0);
1516 Glib::Threads::RWLock::WriterLock lm (_lock);
1518 /* first, determine s & e, two iterators that define the range of points
1519 affected by this operation
1522 if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) == _events.end()) {
1526 /* and the last that is at or after `end' */
1528 e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1531 /* if "start" isn't the location of an existing point,
1532 evaluate the curve to get a value for the start. Add a point to
1533 both the existing event list, and if its not a "clear" operation,
1534 to the copy ("nal") as well.
1536 Note that the time positions of the points in each list are different
1537 because we want the copy ("nal") to have a zero time reference.
1541 /* before we begin any cut/clear operations, get the value of the curve
1545 double end_value = unlocked_eval (end);
1547 if ((*s)->when != start) {
1549 double val = unlocked_eval (start);
1551 if (op == 0) { // cut
1552 if (start > _events.front()->when) {
1553 _events.insert (s, (new ControlEvent (start, val)));
1557 if (op != 2) { // ! clear
1558 nal->_events.push_back (new ControlEvent (0, val));
1562 for (iterator x = s; x != e; ) {
1564 /* adjust new points to be relative to start, which
1565 has been set to zero.
1569 nal->_events.push_back (new ControlEvent ((*x)->when - start, (*x)->value));
1573 x = _events.erase (x);
1579 if (e == _events.end() || (*e)->when != end) {
1581 /* only add a boundary point if there is a point after "end"
1584 if (op == 0 && (e != _events.end() && end < (*e)->when)) { // cut
1585 _events.insert (e, new ControlEvent (end, end_value));
1588 if (op != 2 && (e != _events.end() && end < (*e)->when)) { // cut/copy
1589 nal->_events.push_back (new ControlEvent (end - start, end_value));
1593 unlocked_invalidate_insert_iterator ();
1598 maybe_signal_changed ();
1605 boost::shared_ptr<ControlList>
1606 ControlList::cut (double start, double end)
1608 return cut_copy_clear (start, end, 0);
1611 boost::shared_ptr<ControlList>
1612 ControlList::copy (double start, double end)
1614 return cut_copy_clear (start, end, 1);
1618 ControlList::clear (double start, double end)
1620 cut_copy_clear (start, end, 2);
1623 /** @param pos Position in model coordinates */
1625 ControlList::paste (const ControlList& alist, double pos, float /*times*/)
1627 if (alist._events.empty()) {
1632 Glib::Threads::RWLock::WriterLock lm (_lock);
1636 ControlEvent cp (pos, 0.0);
1638 where = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1640 for (const_iterator i = alist.begin();i != alist.end(); ++i) {
1641 double value = (*i)->value;
1642 if (alist.parameter() != parameter()) {
1643 const ParameterDescriptor& src_desc = alist.descriptor();
1645 value -= src_desc.lower; // translate to 0-relative
1646 value /= (src_desc.upper - src_desc.lower); // normalize range
1647 value *= (_desc.upper - _desc.lower); // scale to our range
1648 value += _desc.lower; // translate to our offset
1650 _events.insert (where, new ControlEvent((*i)->when + pos, value));
1651 end = (*i)->when + pos;
1655 /* move all points after the insertion along the timeline by
1659 while (where != _events.end()) {
1661 if ((*where)->when <= end) {
1664 _events.erase(where);
1672 unlocked_invalidate_insert_iterator ();
1676 maybe_signal_changed ();
1680 /** Move automation around according to a list of region movements.
1681 * @param return true if anything was changed, otherwise false (ie nothing needed changing)
1684 ControlList::move_ranges (const list< RangeMove<double> >& movements)
1686 typedef list< RangeMove<double> > RangeMoveList;
1689 Glib::Threads::RWLock::WriterLock lm (_lock);
1691 /* a copy of the events list before we started moving stuff around */
1692 EventList old_events = _events;
1694 /* clear the source and destination ranges in the new list */
1695 bool things_erased = false;
1696 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1698 if (erase_range_internal (i->from, i->from + i->length, _events)) {
1699 things_erased = true;
1702 if (erase_range_internal (i->to, i->to + i->length, _events)) {
1703 things_erased = true;
1707 /* if nothing was erased, there is nothing to do */
1708 if (!things_erased) {
1712 /* copy the events into the new list */
1713 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1714 iterator j = old_events.begin ();
1715 const double limit = i->from + i->length;
1716 const double dx = i->to - i->from;
1717 while (j != old_events.end () && (*j)->when <= limit) {
1718 if ((*j)->when >= i->from) {
1719 ControlEvent* ev = new ControlEvent (**j);
1721 _events.push_back (ev);
1728 _events.sort (event_time_less_than);
1729 unlocked_invalidate_insert_iterator ();
1731 _sort_pending = true;
1737 maybe_signal_changed ();
1742 ControlList::set_interpolation (InterpolationStyle s)
1744 if (_interpolation == s) {
1749 InterpolationChanged (s); /* EMIT SIGNAL */
1753 ControlList::operator!= (ControlList const & other) const
1755 if (_events.size() != other._events.size()) {
1759 EventList::const_iterator i = _events.begin ();
1760 EventList::const_iterator j = other._events.begin ();
1762 while (i != _events.end() && (*i)->when == (*j)->when && (*i)->value == (*j)->value) {
1767 if (i != _events.end ()) {
1772 _parameter != other._parameter ||
1773 _interpolation != other._interpolation ||
1774 _min_yval != other._min_yval ||
1775 _max_yval != other._max_yval ||
1776 _default_value != other._default_value
1781 ControlList::dump (ostream& o)
1783 /* NOT LOCKED ... for debugging only */
1785 for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
1786 o << (*x)->value << " @ " << (uint64_t) (*x)->when << endl;
1790 } // namespace Evoral