diff options
Diffstat (limited to 'libs/evoral/src/ControlList.cpp')
-rw-r--r-- | libs/evoral/src/ControlList.cpp | 378 |
1 files changed, 215 insertions, 163 deletions
diff --git a/libs/evoral/src/ControlList.cpp b/libs/evoral/src/ControlList.cpp index 72b032e0cf..b49b294288 100644 --- a/libs/evoral/src/ControlList.cpp +++ b/libs/evoral/src/ControlList.cpp @@ -45,7 +45,6 @@ ControlList::ControlList (const Parameter& id) _max_yval = id.max(); _max_xval = 0; // means "no limit" _default_value = 0; - _rt_insertion_point = _events.end(); _lookup_cache.left = -1; _lookup_cache.range.first = _events.end(); _search_cache.left = -1; @@ -64,7 +63,6 @@ ControlList::ControlList (const ControlList& other) _max_yval = other._max_yval; _max_xval = other._max_xval; _default_value = other._default_value; - _rt_insertion_point = _events.end(); _lookup_cache.range.first = _events.end(); _search_cache.first = _events.end(); _sort_pending = false; @@ -87,7 +85,6 @@ ControlList::ControlList (const ControlList& other, double start, double end) _max_yval = other._max_yval; _max_xval = other._max_xval; _default_value = other._default_value; - _rt_insertion_point = _events.end(); _lookup_cache.range.first = _events.end(); _search_cache.first = _events.end(); _sort_pending = false; @@ -110,6 +107,13 @@ ControlList::~ControlList() for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) { delete (*x); } + + for (list<NascentInfo*>::iterator n = nascent.begin(); n != nascent.end(); ++n) { + for (EventList::iterator x = (*n)->events.begin(); x != (*n)->events.end(); ++x) { + delete *x; + } + delete (*n); + } delete _curve; } @@ -203,7 +207,8 @@ ControlList::extend_to (double when) return true; } -void ControlList::_x_scale (double factor) +void +ControlList::_x_scale (double factor) { for (iterator i = _events.begin(); i != _events.end(); ++i) { (*i)->when = floor ((*i)->when * factor); @@ -213,90 +218,165 @@ void ControlList::_x_scale (double factor) } void -ControlList::reposition_for_rt_add (double /*when*/) +ControlList::write_pass_finished (double when) { - _rt_insertion_point = _events.end(); + merge_nascent (when); } void -ControlList::rt_add (double when, double value) +ControlList::merge_nascent (double when) { - //cerr << "RT: alist " << this << " add " << value << " @ " << when << endl; - - { - Glib::Mutex::Lock lm (_lock); - - iterator where; - ControlEvent cp (when, 0.0); - bool done = false; - - if ((_rt_insertion_point != _events.end()) && ((*_rt_insertion_point)->when < when) ) { - - /* we have a previous insertion point, so we should delete - everything between it and the position where we are going - to insert this point. - */ - - iterator after = _rt_insertion_point; - - if (++after != _events.end()) { - iterator far = after; - - while (far != _events.end()) { - if ((*far)->when > when) { - break; - } - ++far; - } - - if (_new_value) { - where = far; - _rt_insertion_point = where; - - if ((*where)->when == when) { - (*where)->value = value; - done = true; - } - } else { - where = _events.erase (after, far); - } - - } else { - - where = after; - - } - - iterator previous = _rt_insertion_point; - --previous; - - if (_rt_insertion_point != _events.begin() && (*_rt_insertion_point)->value == value && (*previous)->value == value) { - (*_rt_insertion_point)->when = when; - done = true; - - } - - } else { + { + Glib::Mutex::Lock lm (_lock); + + if (nascent.empty()) { + return; + } + + for (list<NascentInfo*>::iterator n = nascent.begin(); n != nascent.end(); ++n) { + + NascentInfo* ninfo = *n; + EventList& nascent_events (ninfo->events); + bool need_adjacent_start_clamp; + bool need_adjacent_end_clamp; + + if (nascent_events.empty()) { + delete ninfo; + continue; + } + + if (ninfo->start_time < 0.0) { + ninfo->start_time = nascent_events.front()->when; + } + + if (ninfo->end_time < 0.0) { + ninfo->end_time = when; + } + + bool preexisting = !_events.empty(); + + if (!preexisting) { + + _events = nascent_events; + + } else if (ninfo->end_time < _events.front()->when) { + + /* all points in nascent are before the first existing point */ + + _events.insert (_events.begin(), nascent_events.begin(), nascent_events.end()); + + } else if (ninfo->start_time > _events.back()->when) { + + /* all points in nascent are after the last existing point */ + + _events.insert (_events.end(), nascent_events.begin(), nascent_events.end()); + + } else { + + /* find the range that overaps with nascent events, + and insert the contents of nascent events. + */ + + iterator i; + iterator range_begin = _events.end(); + iterator range_end = _events.end(); + double end_value = unlocked_eval (ninfo->end_time); + double start_value = unlocked_eval (ninfo->start_time - 1); + + need_adjacent_end_clamp = true; + need_adjacent_start_clamp = true; + + for (i = _events.begin(); i != _events.end(); ++i) { + + if ((*i)->when == ninfo->start_time) { + /* existing point at same time, remove it + and the consider the next point instead. + */ + i = _events.erase (i); + + if (i == _events.end()) { + break; + } + + if (range_begin == _events.end()) { + range_begin = i; + need_adjacent_start_clamp = false; + } else { + need_adjacent_end_clamp = false; + } + + if ((*i)->when > ninfo->end_time) { + range_end = i; + break; + } + + } else if ((*i)->when > ninfo->start_time) { + + if (range_begin == _events.end()) { + range_begin = i; + } + + if ((*i)->when > ninfo->end_time) { + range_end = i; + break; + } + } + } + + assert (range_begin != _events.end()); + + if (range_begin != _events.begin()) { + /* clamp point before */ + if (need_adjacent_start_clamp) { + _events.insert (range_begin, new ControlEvent (ninfo->start_time, start_value)); + } + } + + _events.insert (range_begin, nascent_events.begin(), nascent_events.end()); + + if (range_end != _events.end()) { + /* clamp point after */ + if (need_adjacent_end_clamp) { + _events.insert (range_begin, new ControlEvent (ninfo->end_time, end_value)); + } + } + + _events.erase (range_begin, range_end); + } + + delete ninfo; + } + + nascent.clear (); + + if (writing()) { + nascent.push_back (new NascentInfo (false)); + } + } - where = lower_bound (_events.begin(), _events.end(), &cp, time_comparator); + maybe_signal_changed (); +} - if (where != _events.end()) { - if ((*where)->when == when) { - (*where)->value = value; - done = true; - } - } - } +void +ControlList::rt_add (double when, double value) +{ + // this is for automation recording + + if (touch_enabled() && !touching()) { + return; + } - if (!done) { - _rt_insertion_point = _events.insert (where, new ControlEvent (when, value)); - } + //cerr << "RT: alist " << this << " add " << value << " @ " << when << endl; - _new_value = false; - mark_dirty (); - } + Glib::Mutex::Lock lm (_lock, Glib::TRY_LOCK); - maybe_signal_changed (); + if (lm.locked()) { + assert (!nascent.empty()); + if (!nascent.back()->events.empty()) { + assert (when > nascent.back()->events.back()->when); + } + nascent.back()->events.push_back (new ControlEvent (when, value)); + } } void @@ -336,7 +416,6 @@ ControlList::add (double when, double value) if (insert) { _events.insert (insertion_point, new ControlEvent (when, value)); - reposition_for_rt_add (0); } @@ -352,7 +431,6 @@ ControlList::erase (iterator i) { Glib::Mutex::Lock lm (_lock); _events.erase (i); - reposition_for_rt_add (0); mark_dirty (); } maybe_signal_changed (); @@ -364,7 +442,6 @@ ControlList::erase (iterator start, iterator end) { Glib::Mutex::Lock lm (_lock); _events.erase (start, end); - reposition_for_rt_add (0); mark_dirty (); } maybe_signal_changed (); @@ -411,7 +488,6 @@ ControlList::erase_range (double start, double endt) erased = erase_range_internal (start, endt, _events); if (erased) { - reposition_for_rt_add (0); mark_dirty (); } @@ -662,7 +738,6 @@ ControlList::truncate_end (double last_coordinate) _events.back()->value = last_val; } - reposition_for_rt_add (0); mark_dirty(); } @@ -762,8 +837,6 @@ ControlList::truncate_start (double overall_length) _events.push_front (new ControlEvent (0, first_legal_value)); } - reposition_for_rt_add (0); - mark_dirty(); } @@ -1115,35 +1188,6 @@ ControlList::rt_safe_earliest_event_linear_unlocked (double start, double& x, do } } -boost::shared_ptr<ControlList> -ControlList::cut (iterator start, iterator end) -{ - boost::shared_ptr<ControlList> nal = create (_parameter); - - { - Glib::Mutex::Lock lm (_lock); - - for (iterator x = start; x != end; ) { - iterator tmp; - - tmp = x; - ++tmp; - - nal->_events.push_back (new ControlEvent (**x)); - _events.erase (x); - - reposition_for_rt_add (0); - - x = tmp; - } - - mark_dirty (); - } - - maybe_signal_changed (); - - return nal; -} /** @param start Start position in model coordinates. * @param end End position in model coordinates. @@ -1153,15 +1197,16 @@ boost::shared_ptr<ControlList> ControlList::cut_copy_clear (double start, double end, int op) { boost::shared_ptr<ControlList> nal = create (_parameter); - iterator s, e; - bool changed = false; + ControlEvent cp (start, 0.0); { - Glib::Mutex::Lock lm (_lock); + Glib::Mutex::Lock lm (_lock); + + /* first, determine s & e, two iterators that define the range of points + affected by this operation + */ - /* find the first event in our list that is at or before `start' in time */ - ControlEvent cp (start, 0.0); if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) == _events.end()) { return nal; } @@ -1170,70 +1215,79 @@ ControlList::cut_copy_clear (double start, double end, int op) cp.when = end; e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator); - if (op != 2 && (*s)->when != start) { - nal->_events.push_back (new ControlEvent (0, unlocked_eval (start))); - } - for (iterator x = s; x != e; ) { - iterator tmp = x; - ++tmp; + /* if "start" isn't the location of an existing point, + evaluate the curve to get a value for the start. Add a point to + both the existing event list, and if its not a "clear" operation, + to the copy ("nal") as well. + + Note that the time positions of the points in each list are different + because we want the copy ("nal") to have a zero time reference. + */ + + + /* before we begin any cut/clear operations, get the value of the curve + at "end". + */ - changed = true; + double end_value = unlocked_eval (end); + + if ((*s)->when != start) { + + double val = unlocked_eval (start); + + if (op == 0) { // cut + if (start > _events.front()->when) { + _events.insert (s, (new ControlEvent (start, val))); + } + } + + if (op != 2) { // ! clear + nal->_events.push_back (new ControlEvent (0, val)); + } + } + + for (iterator x = s; x != e; ) { /* adjust new points to be relative to start, which has been set to zero. */ - + if (op != 2) { nal->_events.push_back (new ControlEvent ((*x)->when - start, (*x)->value)); } if (op != 1) { - _events.erase (x); - } - - x = tmp; + x = _events.erase (x); + } else { + ++x; + } } + + if (e == _events.end() || (*e)->when != end) { - if (op != 2 && nal->_events.back()->when != end - start) { - nal->_events.push_back (new ControlEvent (end - start, unlocked_eval (end))); - } + /* only add a boundary point if there is a point after "end" + */ + + if (op == 0 && (e != _events.end() && end < (*e)->when)) { // cut + _events.insert (e, new ControlEvent (end, end_value)); + } - if (changed) { - reposition_for_rt_add (0); + if (op != 2 && (e != _events.end() && end < (*e)->when)) { // cut/copy + nal->_events.push_back (new ControlEvent (end - start, end_value)); + } } - mark_dirty (); + mark_dirty (); } - maybe_signal_changed (); + if (op != 1) { + maybe_signal_changed (); + } return nal; - } -boost::shared_ptr<ControlList> -ControlList::copy (iterator start, iterator end) -{ - boost::shared_ptr<ControlList> nal = create (_parameter); - - { - Glib::Mutex::Lock lm (_lock); - - for (iterator x = start; x != end; ) { - iterator tmp; - - tmp = x; - ++tmp; - - nal->_events.push_back (new ControlEvent (**x)); - - x = tmp; - } - } - - return nal; -} boost::shared_ptr<ControlList> ControlList::cut (double start, double end) @@ -1293,7 +1347,6 @@ ControlList::paste (ControlList& alist, double pos, float /*times*/) } } - reposition_for_rt_add (0); mark_dirty (); } @@ -1342,7 +1395,6 @@ ControlList::move_ranges (const list< RangeMove<double> >& movements) _sort_pending = true; } - reposition_for_rt_add (0); mark_dirty (); } |