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)
457 /* this is for making changes from a graphical line editor
460 if (_events.empty()) {
462 /* as long as the point we're adding is not at zero,
463 * add an "anchor" point there.
467 _events.insert (_events.end(), new ControlEvent (0, _default_value));
468 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _default_value));
472 ControlEvent cp (when, 0.0f);
473 iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
474 DEBUG_TRACE (DEBUG::ControlList, string_compose ("editor_add: actually add when= %1 value= %2\n", when, value));
475 _events.insert (i, new ControlEvent (when, value));
479 maybe_signal_changed ();
484 ControlList::maybe_add_insert_guard (double when)
486 if (most_recent_insert_iterator != _events.end()) {
487 if ((*most_recent_insert_iterator)->when - when > 64) {
488 /* Next control point is some distance from where our new point is
489 going to go, so add a new point to avoid changing the shape of
490 the line too much. The insert iterator needs to point to the
491 new control point so that our insert will happen correctly. */
492 most_recent_insert_iterator = _events.insert (
493 most_recent_insert_iterator,
494 new ControlEvent (when + 1, (*most_recent_insert_iterator)->value));
495 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added insert guard point @ %2 = %3\n",
497 (*most_recent_insert_iterator)->value));
502 /** If we would just be adding to a straight line, move the previous point instead. */
504 ControlList::maybe_insert_straight_line (double when, double value)
506 if (_events.empty()) {
510 if (_events.back()->value == value) {
511 // Point b at the final point, which we know exists
512 EventList::iterator b = _events.end();
514 if (b == _events.begin()) {
515 return false; // No previous point
518 // Check the previous point's value
520 if ((*b)->value == value) {
521 /* At least two points with the exact same value (straight
522 line), just move the final point to the new time. */
523 _events.back()->when = when;
524 DEBUG_TRACE (DEBUG::ControlList, string_compose ("final value of %1 moved to %2\n", value, when));
531 ControlList::iterator
532 ControlList::erase_from_iterator_to (iterator iter, double when)
534 while (iter != _events.end()) {
535 if ((*iter)->when < when) {
536 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 erase existing @ %2\n", this, (*iter)->when));
538 iter = _events.erase (iter);
540 } else if ((*iter)->when >= when) {
549 ControlList::add (double when, double value, bool with_guards, bool with_initial)
551 /* this is for making changes from some kind of user interface or
552 control surface (GUI, MIDI, OSC etc)
555 DEBUG_TRACE (DEBUG::ControlList,
556 string_compose ("@%1 add %2 at %3 guards = %4 write pass = %5 (new? %6) at end? %7\n",
557 this, value, when, with_guards, _in_write_pass, new_write_pass,
558 (most_recent_insert_iterator == _events.end())));
560 Glib::Threads::RWLock::WriterLock lm (_lock);
561 ControlEvent cp (when, 0.0f);
562 iterator insertion_point;
564 if (_events.empty() && with_initial) {
566 /* empty: add an "anchor" point if the point we're adding past time 0 */
569 _events.insert (_events.end(), new ControlEvent (0, value));
570 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _default_value));
574 if (_in_write_pass && new_write_pass) {
576 /* first write in a write pass: add guard point if requested */
579 add_guard_point (insert_position);
580 did_write_during_pass = true;
582 /* not adding a guard, but we need to set iterator appropriately */
583 const ControlEvent cp (when, 0.0);
584 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
586 new_write_pass = false;
588 } else if (_in_write_pass &&
589 (most_recent_insert_iterator == _events.end() || when > (*most_recent_insert_iterator)->when)) {
591 /* in write pass: erase from most recent insert to now */
593 if (most_recent_insert_iterator != _events.end()) {
594 /* advance to avoid deleting the last inserted point itself. */
595 ++most_recent_insert_iterator;
598 most_recent_insert_iterator = erase_from_iterator_to(most_recent_insert_iterator, when);
600 maybe_add_insert_guard (when);
603 } else if (!_in_write_pass) {
605 /* not in a write pass: figure out the iterator we should insert in front of */
607 DEBUG_TRACE (DEBUG::ControlList, string_compose ("compute(b) MRI for position %1\n", when));
608 ControlEvent cp (when, 0.0f);
609 most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
612 /* OK, now we're really ready to add a new point */
614 if (most_recent_insert_iterator == _events.end()) {
615 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 appending new point at end\n", this));
617 const bool done = maybe_insert_straight_line (when, value);
619 _events.push_back (new ControlEvent (when, value));
620 DEBUG_TRACE (DEBUG::ControlList, string_compose ("\tactually appended, size now %1\n", _events.size()));
623 most_recent_insert_iterator = _events.end();
624 --most_recent_insert_iterator;
626 } else if ((*most_recent_insert_iterator)->when == when) {
628 if ((*most_recent_insert_iterator)->value != value) {
629 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 reset existing point to new value %2\n", this, value));
631 /* only one point allowed per time point, so add a guard point
632 * before it if needed then reset the value of the point.
635 if ((when > 0) && most_recent_insert_iterator != _events.begin ()) {
636 --most_recent_insert_iterator;
637 double last_when = (*most_recent_insert_iterator)->when;
638 ++most_recent_insert_iterator;
639 if (when - last_when > 64) {
640 add_guard_point (when - 64);
644 (*most_recent_insert_iterator)->value = value;
646 /* if we modified the final value, then its as
647 * if we inserted a new point as far as the
648 * next addition, so make sure we know that.
651 if (_events.back()->when == when) {
652 most_recent_insert_iterator = _events.end();
656 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 same time %2, same value value %3\n", this, when, value));
660 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 insert new point at %2 at iterator at %3\n", this, when, (*most_recent_insert_iterator)->when));
662 const bool done = maybe_insert_straight_line (when, value);
664 maybe_add_insert_guard(when);
668 EventList::iterator x = _events.insert (most_recent_insert_iterator, new ControlEvent (when, value));
669 DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 inserted new value before MRI, size now %2\n", this, _events.size()));
670 most_recent_insert_iterator = x;
677 maybe_signal_changed ();
681 ControlList::erase (iterator i)
684 Glib::Threads::RWLock::WriterLock lm (_lock);
685 if (most_recent_insert_iterator == i) {
686 unlocked_invalidate_insert_iterator ();
691 maybe_signal_changed ();
695 ControlList::erase (iterator start, iterator end)
698 Glib::Threads::RWLock::WriterLock lm (_lock);
699 _events.erase (start, end);
700 unlocked_invalidate_insert_iterator ();
703 maybe_signal_changed ();
706 /** Erase the first event which matches the given time and value */
708 ControlList::erase (double when, double value)
711 Glib::Threads::RWLock::WriterLock lm (_lock);
713 iterator i = begin ();
714 while (i != end() && ((*i)->when != when || (*i)->value != value)) {
720 if (most_recent_insert_iterator == i) {
721 unlocked_invalidate_insert_iterator ();
728 maybe_signal_changed ();
732 ControlList::erase_range (double start, double endt)
737 Glib::Threads::RWLock::WriterLock lm (_lock);
738 erased = erase_range_internal (start, endt, _events);
747 maybe_signal_changed ();
752 ControlList::erase_range_internal (double start, double endt, EventList & events)
755 ControlEvent cp (start, 0.0f);
759 if ((s = lower_bound (events.begin(), events.end(), &cp, time_comparator)) != events.end()) {
761 e = upper_bound (events.begin(), events.end(), &cp, time_comparator);
764 unlocked_invalidate_insert_iterator ();
773 ControlList::slide (iterator before, double distance)
776 Glib::Threads::RWLock::WriterLock lm (_lock);
778 if (before == _events.end()) {
782 while (before != _events.end()) {
783 (*before)->when += distance;
790 maybe_signal_changed ();
794 ControlList::shift (double pos, double frames)
797 Glib::Threads::RWLock::WriterLock lm (_lock);
799 for (iterator i = _events.begin(); i != _events.end(); ++i) {
800 if ((*i)->when >= pos) {
801 (*i)->when += frames;
808 maybe_signal_changed ();
812 ControlList::modify (iterator iter, double when, double val)
814 /* note: we assume higher level logic is in place to avoid this
815 reordering the time-order of control events in the list. ie. all
816 points after *iter are later than when.
820 Glib::Threads::RWLock::WriterLock lm (_lock);
822 (*iter)->when = when;
823 (*iter)->value = val;
824 if (isnan_local (val)) {
829 _events.sort (event_time_less_than);
830 unlocked_invalidate_insert_iterator ();
832 _sort_pending = true;
838 maybe_signal_changed ();
841 std::pair<ControlList::iterator,ControlList::iterator>
842 ControlList::control_points_adjacent (double xval)
844 Glib::Threads::RWLock::ReaderLock lm (_lock);
846 ControlEvent cp (xval, 0.0f);
847 std::pair<iterator,iterator> ret;
849 ret.first = _events.end();
850 ret.second = _events.end();
852 for (i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator); i != _events.end(); ++i) {
854 if (ret.first == _events.end()) {
855 if ((*i)->when >= xval) {
856 if (i != _events.begin()) {
865 if ((*i)->when > xval) {
875 ControlList::freeze ()
890 Glib::Threads::RWLock::WriterLock lm (_lock);
893 _events.sort (event_time_less_than);
894 unlocked_invalidate_insert_iterator ();
895 _sort_pending = false;
901 ControlList::mark_dirty () const
903 _lookup_cache.left = -1;
904 _lookup_cache.range.first = _events.end();
905 _lookup_cache.range.second = _events.end();
906 _search_cache.left = -1;
907 _search_cache.first = _events.end();
910 _curve->mark_dirty();
913 Dirty (); /* EMIT SIGNAL */
917 ControlList::truncate_end (double last_coordinate)
920 Glib::Threads::RWLock::WriterLock lm (_lock);
921 ControlEvent cp (last_coordinate, 0);
922 ControlList::reverse_iterator i;
925 if (_events.empty()) {
929 if (last_coordinate == _events.back()->when) {
933 if (last_coordinate > _events.back()->when) {
938 iterator foo = _events.begin();
941 if (foo == _events.end()) {
943 } else if (++foo == _events.end()) {
950 /* less than 2 points: add a new point */
951 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
954 /* more than 2 points: check to see if the last 2 values
955 are equal. if so, just move the position of the
956 last point. otherwise, add a new point.
959 iterator penultimate = _events.end();
960 --penultimate; /* points at last point */
961 --penultimate; /* points at the penultimate point */
963 if (_events.back()->value == (*penultimate)->value) {
964 _events.back()->when = last_coordinate;
966 _events.push_back (new ControlEvent (last_coordinate, _events.back()->value));
974 last_val = unlocked_eval (last_coordinate);
975 last_val = max ((double) _min_yval, last_val);
976 last_val = min ((double) _max_yval, last_val);
978 i = _events.rbegin();
980 /* make i point to the last control point */
984 /* now go backwards, removing control points that are
985 beyond the new last coordinate.
988 // FIXME: SLOW! (size() == O(n))
990 uint32_t sz = _events.size();
992 while (i != _events.rend() && sz > 2) {
993 ControlList::reverse_iterator tmp;
998 if ((*i)->when < last_coordinate) {
1002 _events.erase (i.base());
1008 _events.back()->when = last_coordinate;
1009 _events.back()->value = last_val;
1012 unlocked_invalidate_insert_iterator ();
1016 maybe_signal_changed ();
1020 ControlList::truncate_start (double overall_length)
1023 Glib::Threads::RWLock::WriterLock lm (_lock);
1025 double first_legal_value;
1026 double first_legal_coordinate;
1028 if (_events.empty()) {
1029 /* nothing to truncate */
1031 } else if (overall_length == _events.back()->when) {
1032 /* no change in overall length */
1036 if (overall_length > _events.back()->when) {
1038 /* growing at front: duplicate first point. shift all others */
1040 double shift = overall_length - _events.back()->when;
1043 for (np = 0, i = _events.begin(); i != _events.end(); ++i, ++np) {
1044 (*i)->when += shift;
1049 /* less than 2 points: add a new point */
1050 _events.push_front (new ControlEvent (0, _events.front()->value));
1054 /* more than 2 points: check to see if the first 2 values
1055 are equal. if so, just move the position of the
1056 first point. otherwise, add a new point.
1059 iterator second = _events.begin();
1060 ++second; /* points at the second point */
1062 if (_events.front()->value == (*second)->value) {
1063 /* first segment is flat, just move start point back to zero */
1064 _events.front()->when = 0;
1066 /* leave non-flat segment in place, add a new leading point. */
1067 _events.push_front (new ControlEvent (0, _events.front()->value));
1073 /* shrinking at front */
1075 first_legal_coordinate = _events.back()->when - overall_length;
1076 first_legal_value = unlocked_eval (first_legal_coordinate);
1077 first_legal_value = max (_min_yval, first_legal_value);
1078 first_legal_value = min (_max_yval, first_legal_value);
1080 /* remove all events earlier than the new "front" */
1082 i = _events.begin();
1084 while (i != _events.end() && !_events.empty()) {
1085 ControlList::iterator tmp;
1090 if ((*i)->when > first_legal_coordinate) {
1100 /* shift all remaining points left to keep their same
1104 for (i = _events.begin(); i != _events.end(); ++i) {
1105 (*i)->when -= first_legal_coordinate;
1108 /* add a new point for the interpolated new value */
1110 _events.push_front (new ControlEvent (0, first_legal_value));
1113 unlocked_invalidate_insert_iterator ();
1117 maybe_signal_changed ();
1121 ControlList::unlocked_eval (double x) const
1123 pair<EventList::iterator,EventList::iterator> range;
1129 const_iterator length_check_iter = _events.begin();
1130 for (npoints = 0; npoints < 4; ++npoints, ++length_check_iter) {
1131 if (length_check_iter == _events.end()) {
1138 return _default_value;
1141 return _events.front()->value;
1144 if (x >= _events.back()->when) {
1145 return _events.back()->value;
1146 } else if (x <= _events.front()->when) {
1147 return _events.front()->value;
1150 lpos = _events.front()->when;
1151 lval = _events.front()->value;
1152 upos = _events.back()->when;
1153 uval = _events.back()->value;
1155 if (_interpolation == Discrete) {
1159 /* linear interpolation betweeen the two points */
1160 fraction = (double) (x - lpos) / (double) (upos - lpos);
1161 return lval + (fraction * (uval - lval));
1164 if (x >= _events.back()->when) {
1165 return _events.back()->value;
1166 } else if (x <= _events.front()->when) {
1167 return _events.front()->value;
1170 return multipoint_eval (x);
1173 abort(); /*NOTREACHED*/ /* stupid gcc */
1174 return _default_value;
1178 ControlList::multipoint_eval (double x) const
1184 /* "Stepped" lookup (no interpolation) */
1185 /* FIXME: no cache. significant? */
1186 if (_interpolation == Discrete) {
1187 const ControlEvent cp (x, 0);
1188 EventList::const_iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
1190 // shouldn't have made it to multipoint_eval
1191 assert(i != _events.end());
1193 if (i == _events.begin() || (*i)->when == x)
1196 return (*(--i))->value;
1199 /* Only do the range lookup if x is in a different range than last time
1200 * this was called (or if the lookup cache has been marked "dirty" (left<0) */
1201 if ((_lookup_cache.left < 0) ||
1202 ((_lookup_cache.left > x) ||
1203 (_lookup_cache.range.first == _events.end()) ||
1204 ((*_lookup_cache.range.second)->when < x))) {
1206 const ControlEvent cp (x, 0);
1208 _lookup_cache.range = equal_range (_events.begin(), _events.end(), &cp, time_comparator);
1211 pair<const_iterator,const_iterator> range = _lookup_cache.range;
1213 if (range.first == range.second) {
1215 /* x does not exist within the list as a control point */
1217 _lookup_cache.left = x;
1219 if (range.first != _events.begin()) {
1221 lpos = (*range.first)->when;
1222 lval = (*range.first)->value;
1224 /* we're before the first point */
1225 // return _default_value;
1226 return _events.front()->value;
1229 if (range.second == _events.end()) {
1230 /* we're after the last point */
1231 return _events.back()->value;
1234 upos = (*range.second)->when;
1235 uval = (*range.second)->value;
1237 /* linear interpolation betweeen the two points
1241 fraction = (double) (x - lpos) / (double) (upos - lpos);
1242 return lval + (fraction * (uval - lval));
1246 /* x is a control point in the data */
1247 _lookup_cache.left = -1;
1248 return (*range.first)->value;
1252 ControlList::build_search_cache_if_necessary (double start) const
1254 if (_events.empty()) {
1255 /* Empty, nothing to cache, move to end. */
1256 _search_cache.first = _events.end();
1257 _search_cache.left = 0;
1259 } else if ((_search_cache.left < 0) || (_search_cache.left > start)) {
1260 /* Marked dirty (left < 0), or we're too far forward, re-search. */
1262 const ControlEvent start_point (start, 0);
1264 _search_cache.first = lower_bound (_events.begin(), _events.end(), &start_point, time_comparator);
1265 _search_cache.left = start;
1268 /* We now have a search cache that is not too far right, but it may be too
1269 far left and need to be advanced. */
1271 while (_search_cache.first != end() && (*_search_cache.first)->when < start) {
1272 ++_search_cache.first;
1274 _search_cache.left = start;
1277 /** Get the earliest event after \a start using the current interpolation style.
1279 * If an event is found, \a x and \a y are set to its coordinates.
1281 * \param inclusive Include events with timestamp exactly equal to \a start
1282 * \return true if event is found (and \a x and \a y are valid).
1285 ControlList::rt_safe_earliest_event (double start, double& x, double& y, bool inclusive) const
1287 // FIXME: It would be nice if this was unnecessary..
1288 Glib::Threads::RWLock::ReaderLock lm(_lock, Glib::Threads::TRY_LOCK);
1293 return rt_safe_earliest_event_unlocked (start, x, y, inclusive);
1297 /** Get the earliest event after \a start using the current interpolation style.
1299 * If an event is found, \a x and \a y are set to its coordinates.
1301 * \param inclusive Include events with timestamp exactly equal to \a start
1302 * \return true if event is found (and \a x and \a y are valid).
1305 ControlList::rt_safe_earliest_event_unlocked (double start, double& x, double& y, bool inclusive) const
1307 if (_interpolation == Discrete) {
1308 return rt_safe_earliest_event_discrete_unlocked(start, x, y, inclusive);
1310 return rt_safe_earliest_event_linear_unlocked(start, x, y, inclusive);
1315 /** Get the earliest event after \a start without interpolation.
1317 * If an event is found, \a x and \a y are set to its coordinates.
1319 * \param inclusive Include events with timestamp exactly equal to \a start
1320 * \return true if event is found (and \a x and \a y are valid).
1323 ControlList::rt_safe_earliest_event_discrete_unlocked (double start, double& x, double& y, bool inclusive) const
1325 build_search_cache_if_necessary (start);
1327 if (_search_cache.first != _events.end()) {
1328 const ControlEvent* const first = *_search_cache.first;
1330 const bool past_start = (inclusive ? first->when >= start : first->when > start);
1332 /* Earliest points is in range, return it */
1338 /* Move left of cache to this point
1339 * (Optimize for immediate call this cycle within range) */
1340 _search_cache.left = x;
1341 ++_search_cache.first;
1350 /* No points in range */
1356 /** Get the earliest time the line crosses an integer (Linear interpolation).
1358 * If an event is found, \a x and \a y are set to its coordinates.
1360 * \param inclusive Include events with timestamp exactly equal to \a start
1361 * \return true if event is found (and \a x and \a y are valid).
1364 ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, double& y, bool inclusive) const
1366 // cout << "earliest_event(start: " << start << ", x: " << x << ", y: " << y << ", inclusive: " << inclusive << ")" << endl;
1368 const_iterator length_check_iter = _events.begin();
1369 if (_events.empty()) { // 0 events
1371 } else if (_events.end() == ++length_check_iter) { // 1 event
1372 return rt_safe_earliest_event_discrete_unlocked (start, x, y, inclusive);
1375 // Hack to avoid infinitely repeating the same event
1376 build_search_cache_if_necessary (start);
1378 if (_search_cache.first != _events.end()) {
1380 const ControlEvent* first = NULL;
1381 const ControlEvent* next = NULL;
1383 if (_search_cache.first == _events.begin() || (*_search_cache.first)->when <= start) {
1384 /* Step is after first */
1385 first = *_search_cache.first;
1386 ++_search_cache.first;
1387 if (_search_cache.first == _events.end()) {
1390 next = *_search_cache.first;
1393 /* Step is before first */
1394 const_iterator prev = _search_cache.first;
1397 next = *_search_cache.first;
1400 if (inclusive && first->when == start) {
1403 /* Move left of cache to this point
1404 * (Optimize for immediate call this cycle within range) */
1405 _search_cache.left = x;
1407 } else if (next->when < start || (!inclusive && next->when == start)) {
1408 /* "Next" is before the start, no points left. */
1412 if (fabs(first->value - next->value) <= 1) {
1413 if (next->when > start) {
1416 /* Move left of cache to this point
1417 * (Optimize for immediate call this cycle within range) */
1418 _search_cache.left = x;
1425 const double slope = (next->value - first->value) / (double)(next->when - first->when);
1426 //cerr << "start y: " << start_y << endl;
1428 //y = first->value + (slope * fabs(start - first->when));
1431 if (first->value < next->value) // ramping up
1433 else // ramping down
1436 x = first->when + (y - first->value) / (double)slope;
1438 while ((inclusive && x < start) || (x <= start && y != next->value)) {
1440 if (first->value < next->value) // ramping up
1442 else // ramping down
1445 x = first->when + (y - first->value) / (double)slope;
1448 /*cerr << first->value << " @ " << first->when << " ... "
1449 << next->value << " @ " << next->when
1450 << " = " << y << " @ " << x << endl;*/
1452 assert( (y >= first->value && y <= next->value)
1453 || (y <= first->value && y >= next->value) );
1456 const bool past_start = (inclusive ? x >= start : x > start);
1458 /* Move left of cache to this point
1459 * (Optimize for immediate call this cycle within range) */
1460 _search_cache.left = x;
1461 assert(inclusive ? x >= start : x > start);
1469 _search_cache.left = x;
1474 /* No points in the future, so no steps (towards them) in the future */
1480 /** @param start Start position in model coordinates.
1481 * @param end End position in model coordinates.
1482 * @param op 0 = cut, 1 = copy, 2 = clear.
1484 boost::shared_ptr<ControlList>
1485 ControlList::cut_copy_clear (double start, double end, int op)
1487 boost::shared_ptr<ControlList> nal = create (_parameter, _desc);
1489 ControlEvent cp (start, 0.0);
1492 Glib::Threads::RWLock::WriterLock lm (_lock);
1494 /* first, determine s & e, two iterators that define the range of points
1495 affected by this operation
1498 if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) == _events.end()) {
1502 /* and the last that is at or after `end' */
1504 e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1507 /* if "start" isn't the location of an existing point,
1508 evaluate the curve to get a value for the start. Add a point to
1509 both the existing event list, and if its not a "clear" operation,
1510 to the copy ("nal") as well.
1512 Note that the time positions of the points in each list are different
1513 because we want the copy ("nal") to have a zero time reference.
1517 /* before we begin any cut/clear operations, get the value of the curve
1521 double end_value = unlocked_eval (end);
1523 if ((*s)->when != start) {
1525 double val = unlocked_eval (start);
1527 if (op == 0) { // cut
1528 if (start > _events.front()->when) {
1529 _events.insert (s, (new ControlEvent (start, val)));
1533 if (op != 2) { // ! clear
1534 nal->_events.push_back (new ControlEvent (0, val));
1538 for (iterator x = s; x != e; ) {
1540 /* adjust new points to be relative to start, which
1541 has been set to zero.
1545 nal->_events.push_back (new ControlEvent ((*x)->when - start, (*x)->value));
1549 x = _events.erase (x);
1555 if (e == _events.end() || (*e)->when != end) {
1557 /* only add a boundary point if there is a point after "end"
1560 if (op == 0 && (e != _events.end() && end < (*e)->when)) { // cut
1561 _events.insert (e, new ControlEvent (end, end_value));
1564 if (op != 2 && (e != _events.end() && end < (*e)->when)) { // cut/copy
1565 nal->_events.push_back (new ControlEvent (end - start, end_value));
1569 unlocked_invalidate_insert_iterator ();
1574 maybe_signal_changed ();
1581 boost::shared_ptr<ControlList>
1582 ControlList::cut (double start, double end)
1584 return cut_copy_clear (start, end, 0);
1587 boost::shared_ptr<ControlList>
1588 ControlList::copy (double start, double end)
1590 return cut_copy_clear (start, end, 1);
1594 ControlList::clear (double start, double end)
1596 cut_copy_clear (start, end, 2);
1599 /** @param pos Position in model coordinates */
1601 ControlList::paste (const ControlList& alist, double pos, float /*times*/)
1603 if (alist._events.empty()) {
1608 Glib::Threads::RWLock::WriterLock lm (_lock);
1612 ControlEvent cp (pos, 0.0);
1614 where = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
1616 for (const_iterator i = alist.begin();i != alist.end(); ++i) {
1617 double value = (*i)->value;
1618 if (alist.parameter() != parameter()) {
1619 const ParameterDescriptor& src_desc = alist.descriptor();
1621 value -= src_desc.lower; // translate to 0-relative
1622 value /= (src_desc.upper - src_desc.lower); // normalize range
1623 value *= (_desc.upper - _desc.lower); // scale to our range
1624 value += _desc.lower; // translate to our offset
1626 _events.insert (where, new ControlEvent((*i)->when + pos, value));
1627 end = (*i)->when + pos;
1631 /* move all points after the insertion along the timeline by
1635 while (where != _events.end()) {
1637 if ((*where)->when <= end) {
1640 _events.erase(where);
1648 unlocked_invalidate_insert_iterator ();
1652 maybe_signal_changed ();
1656 /** Move automation around according to a list of region movements.
1657 * @param return true if anything was changed, otherwise false (ie nothing needed changing)
1660 ControlList::move_ranges (const list< RangeMove<double> >& movements)
1662 typedef list< RangeMove<double> > RangeMoveList;
1665 Glib::Threads::RWLock::WriterLock lm (_lock);
1667 /* a copy of the events list before we started moving stuff around */
1668 EventList old_events = _events;
1670 /* clear the source and destination ranges in the new list */
1671 bool things_erased = false;
1672 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1674 if (erase_range_internal (i->from, i->from + i->length, _events)) {
1675 things_erased = true;
1678 if (erase_range_internal (i->to, i->to + i->length, _events)) {
1679 things_erased = true;
1683 /* if nothing was erased, there is nothing to do */
1684 if (!things_erased) {
1688 /* copy the events into the new list */
1689 for (RangeMoveList::const_iterator i = movements.begin (); i != movements.end (); ++i) {
1690 iterator j = old_events.begin ();
1691 const double limit = i->from + i->length;
1692 const double dx = i->to - i->from;
1693 while (j != old_events.end () && (*j)->when <= limit) {
1694 if ((*j)->when >= i->from) {
1695 ControlEvent* ev = new ControlEvent (**j);
1697 _events.push_back (ev);
1704 _events.sort (event_time_less_than);
1705 unlocked_invalidate_insert_iterator ();
1707 _sort_pending = true;
1713 maybe_signal_changed ();
1718 ControlList::set_interpolation (InterpolationStyle s)
1720 if (_interpolation == s) {
1725 InterpolationChanged (s); /* EMIT SIGNAL */
1729 ControlList::operator!= (ControlList const & other) const
1731 if (_events.size() != other._events.size()) {
1735 EventList::const_iterator i = _events.begin ();
1736 EventList::const_iterator j = other._events.begin ();
1738 while (i != _events.end() && (*i)->when == (*j)->when && (*i)->value == (*j)->value) {
1743 if (i != _events.end ()) {
1748 _parameter != other._parameter ||
1749 _interpolation != other._interpolation ||
1750 _min_yval != other._min_yval ||
1751 _max_yval != other._max_yval ||
1752 _default_value != other._default_value
1757 ControlList::dump (ostream& o)
1759 /* NOT LOCKED ... for debugging only */
1761 for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
1762 o << (*x)->value << " @ " << (uint64_t) (*x)->when << endl;
1766 } // namespace Evoral