From 45b02538e6a2f8f061e5f57c386b1826d01e08c4 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 10 Jul 2023 11:20:17 -0600 Subject: [PATCH] Evoral: extend ControlList API with ::editor_ordered_points() Much more efficient than adding points 1 by 1 --- libs/evoral/ControlList.cc | 74 ++++++++++++++++++++++++++++++++ libs/evoral/evoral/ControlList.h | 9 ++++ 2 files changed, 83 insertions(+) diff --git a/libs/evoral/ControlList.cc b/libs/evoral/ControlList.cc index 70a1072b82..dc7e20ea5a 100644 --- a/libs/evoral/ControlList.cc +++ b/libs/evoral/ControlList.cc @@ -713,6 +713,80 @@ ControlList::editor_add (timepos_t const& time, double value, bool with_guard) return true; } +bool +ControlList::editor_add_ordered (OrderedPoints const & points, bool with_guard) +{ + /* this is for making changes from a graphical line editor */ + if (points.empty()) { + return false; + } + + { + Glib::Threads::RWLock::WriterLock lm (_lock); + + Temporal::timepos_t earliest = points.front().when; + Temporal::timepos_t latest = points.back().when; + + if (earliest > latest) { + swap (earliest, latest); + } + + (void) erase_range_internal (earliest, latest, _events); + + /* Get the iterator where we should start insertion */ + + timepos_t when = ensure_time_domain (points.front().when); + ControlEvent xp (when, 0.0f); + iterator i = lower_bound (_events.begin (), _events.end (), &xp, time_comparator); + + if (i != _events.end () && (*i)->when == when) { + return false; + } + + for (auto const & p : points) { + + when = ensure_time_domain (p.when); + + /* clamp new value to allowed range */ + + double value = std::min ((double)_desc.upper, std::max ((double)_desc.lower, p.value)); + + if (_events.empty ()) { + /* as long as the point we're adding is not at zero, + * add an "anchor" point there. + */ + + if (when >= 1) { + _events.insert (_events.end (), new ControlEvent (timepos_t (_time_domain), value)); + DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added value %2 at zero\n", this, value)); + } + } + + insert_position = when; + if (with_guard) { + add_guard_point (p.when, -GUARD_POINT_DELTA (when)); + maybe_add_insert_guard (when); + ControlEvent cp (when, 0.0f); + i = lower_bound (_events.begin (), _events.end (), &cp, time_comparator); + } + + iterator result; + DEBUG_TRACE (DEBUG::ControlList, string_compose ("editor_add: actually add when= %1 value= %2\n", when, value)); + result = _events.insert (i, new ControlEvent (when, value)); + + if (i == result) { + /* insertion failed, but we don't really care */ + } + } + + mark_dirty (); + } + + maybe_signal_changed (); + + return true; +} + void ControlList::maybe_add_insert_guard (timepos_t const& time) { diff --git a/libs/evoral/evoral/ControlList.h b/libs/evoral/evoral/ControlList.h index e835c3523d..5a92f41e85 100644 --- a/libs/evoral/evoral/ControlList.h +++ b/libs/evoral/evoral/ControlList.h @@ -171,6 +171,15 @@ public: */ virtual bool editor_add (Temporal::timepos_t const & when, double value, bool with_guard); + struct OrderedPoint { + Temporal::timepos_t when; + double value; + OrderedPoint (Temporal::timepos_t const & t, double v) : when (t), value (v) {} + }; + typedef std::vector OrderedPoints; + + virtual bool editor_add_ordered (OrderedPoints const &, bool with_guard); + /* to be used only for loading pre-sorted data from saved state */ void fast_simple_add (Temporal::timepos_t const & when, double value);