diff --git a/libs/evoral/ControlList.cc b/libs/evoral/ControlList.cc index 9fd72421a9..83b5412cb0 100644 --- a/libs/evoral/ControlList.cc +++ b/libs/evoral/ControlList.cc @@ -1675,53 +1675,50 @@ ControlList::rt_safe_earliest_event_discrete_unlocked (timepos_t const & start_t * \return true if event is found (and \a x and \a y are valid). */ bool -ControlList::rt_safe_earliest_event_linear_unlocked (Temporal::timepos_t const & start_time, Temporal::timepos_t & x, double& y, bool inclusive, Temporal::timecnt_t min_x_delta) const +ControlList::rt_safe_earliest_event_linear_unlocked ( + Temporal::timepos_t const & start_time, + Temporal::timepos_t & x, + double & y, + bool inclusive, + Temporal::timecnt_t min_x_delta) const { timepos_t start = start_time; - /* the max value is given as an out-of-bounds default value, when the - true default is zero, but the time-domain is not known at compile - time. This allows us to reset it to zero with the correct time - domain (equality comparisons across time domains where the actual - scalar value is zero should always be cheap, but that's not true of - other operators such as >, < etc.) - */ + /* The max value is given as an out-of-bounds default value, when the true + default is zero, but the time-domain is not known at compile time. This + allows us to reset it to zero with the correct time domain (equality + comparisons across time domains where the actual scalar value is zero + should always be cheap, but that's not true of other operators such as + >, < etc.) */ if (min_x_delta == Temporal::timecnt_t::max()) { min_x_delta = Temporal::timecnt_t (time_domain()); } - // cout << "earliest_event(start: " << start << ", x: " << x << ", y: " << y << ", inclusive: " << inclusive << ") mxd " << min_x_delta << endl; - const_iterator length_check_iter = _events.begin(); if (_events.empty()) { - /* no events, so we cannot interpolate */ + // No events, so we can't interpolate return false; } else if (_events.end() == ++length_check_iter) { - /* one event, which decomposes to the same logic as the discrete one */ + // One event, which decomposes to the same logic as the discrete one return rt_safe_earliest_event_discrete_unlocked (start + min_x_delta, x, y, inclusive); } if (min_x_delta > 0) { - /* if there is an event between [start ... start + min_x_delta], use it, - */ + // If there is an event between [start ... start + min_x_delta], use it build_search_cache_if_necessary (start); const ControlEvent* first = *_search_cache.first; if (_search_cache.first != _events.end()) { if (((first->when > start) || (inclusive && first->when == start)) && first->when < start + min_x_delta) { x = first->when; y = first->value; - /* Move left of cache to this point - * (Optimize for immediate call this cycle within range) */ - _search_cache.left = x; - return true; + return _search_cache.advance_to(x); } } } - /* No event between start and start + min_x_delta, so otherwise - * interpolate at start + min_x_delta - */ + /* No event between start and start + min_x_delta, so otherwise interpolate + at start + min_x_delta. */ start += min_x_delta; @@ -1729,7 +1726,7 @@ ControlList::rt_safe_earliest_event_linear_unlocked (Temporal::timepos_t const & build_search_cache_if_necessary (start); if (_search_cache.first == _events.end()) { - /* No points in the future, so no steps (towards them) in the future */ + // No points in the future, so no steps (towards them) in the future return false; } @@ -1737,17 +1734,17 @@ ControlList::rt_safe_earliest_event_linear_unlocked (Temporal::timepos_t const & const ControlEvent* next = NULL; if (_search_cache.first == _events.begin() || (*_search_cache.first)->when <= start) { - /* Start is after first */ + // Start is after first first = *_search_cache.first; ++_search_cache.first; if (_search_cache.first == _events.end()) { - /* no later events, nothing to interpolate towards */ + // No later events, nothing to interpolate towards return false; } next = *_search_cache.first; } else { - /* Start is before first */ + // Start is before first assert (_search_cache.first != _events.begin()); const_iterator prev = _search_cache.first; --prev; @@ -1756,52 +1753,38 @@ ControlList::rt_safe_earliest_event_linear_unlocked (Temporal::timepos_t const & } if (inclusive && first->when == start) { - /* existing point matches start */ - + // Existing point matches start x = first->when; y = first->value; - /* Move left of cache to this point - * (Optimize for immediate call this cycle within range) - */ - _search_cache.left = first->when; - return true; + return _search_cache.advance_to(x); } else if (next->when < start || (!inclusive && next->when == start)) { - /* "Next" is before the start, no points left. */ + // "Next" is before the start, no points left return false; } if (fabs (first->value - next->value) <= 1) { - - /* delta between the two spanning points is <= 1, - consider the next point as the answer, but only if the next - point is actually beyond @param start. - */ + /* The delta between the two spanning points is <= 1, so consider the + next point as the answer, but only if the next point is actually + beyond the start. */ if (next->when > start) { x = next->when; y = next->value; - /* Move left of cache to this point - * (Optimize for immediate call this cycle within range) */ - _search_cache.left = next->when; - return true; + return _search_cache.advance_to(x); } else { - /* no suitable point can be determined */ + // No suitable point can be determined return false; } } - const double slope = (next->value - first->value) / (double) first->when.distance (next->when).distance().val(); + enum Direction { UP, DOWN }; - //cerr << "start y: " << start_y << endl; + const Direction direction = (first->value < next->value) ? UP : DOWN; + const double y_distance = next->value - first->value; + const double x_distance = (double)first->when.distance (next->when).distance ().val (); + const double slope = y_distance / x_distance; - //y = first->value + (slope * fabs(start - first->when)); - y = first->value; - - if (first->value < next->value) { // ramping up - y = ceil(y); - } else { // ramping down - y = floor(y); - } + y = (direction == UP) ? ceil (first->value) : floor (first->value); if (_time_domain == AudioTime) { x = first->when + timepos_t (samplepos_t ((y - first->value) / (double)slope)); @@ -1809,16 +1792,12 @@ ControlList::rt_safe_earliest_event_linear_unlocked (Temporal::timepos_t const & x = first->when + timepos_t::from_ticks ((y - first->value) / (double)slope); } - /* Now iterate until x has a suitable relationship to start (depending - * on the value of @param inclusive. Either less than @param start or - * less-than-or-equal with y not yet reaching the value of the next - * point. - */ - - const double delta = (first->value < next->value) ? 1.0 /* ramping up */ : -1.0; /* ramping down */ + /* Now scan until x has a suitable relationship to start, depending on the + * value of `inclusive`. It must be < start, or <= start with y not yet + * reaching the value of the next point. */ + const double delta = (direction == UP) ? 1.0 : -1.0; while ((inclusive && x < start) || (x <= start && y != next->value)) { - y += delta; if (_time_domain == AudioTime) { @@ -1831,27 +1810,16 @@ ControlList::rt_safe_earliest_event_linear_unlocked (Temporal::timepos_t const & assert ((y >= first->value && y <= next->value) || (y <= first->value && y >= next->value) ); const bool past_start = (inclusive ? x >= start : x > start); - if (past_start) { - /* Move left of cache to this point - * (Optimize for immediate call this cycle within range) */ - _search_cache.left = x; assert(inclusive ? x >= start : x > start); - return true; + return _search_cache.advance_to(x); } - if (inclusive) { - x = next->when; - _search_cache.left = next->when; - } else { - x = start; - _search_cache.left = x; - } + x = inclusive ? next->when : start; - return true; + return _search_cache.advance_to(x); } - /** @param start Start position in model coordinates. * @param end End position in model coordinates. * @param op 0 = cut, 1 = copy, 2 = clear. diff --git a/libs/evoral/evoral/ControlList.h b/libs/evoral/evoral/ControlList.h index 99258e788a..8f6655e25e 100644 --- a/libs/evoral/evoral/ControlList.h +++ b/libs/evoral/evoral/ControlList.h @@ -290,6 +290,8 @@ public: SearchCache () : left (std::numeric_limits::max()) {} Temporal::timepos_t left; /* leftmost x coordinate used when finding "first" */ ControlList::const_iterator first; + + bool advance_to(Temporal::timepos_t new_left) { left = new_left; return true; } }; /** @return the list of events */