+bool
+ControlList::editor_add (double when, double value, bool with_guard)
+{
+ /* this is for making changes from a graphical line editor
+ */
+
+ ControlEvent cp (when, 0.0f);
+ iterator i = lower_bound (_events.begin(), _events.end(), &cp, time_comparator);
+
+ if (i != _events.end () && (*i)->when == when) {
+ return false;
+ }
+
+ 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 (0, value));
+ DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added value %2 at zero\n", this, value));
+ }
+ }
+
+ insert_position = when;
+ if (with_guard) {
+ if (when > 64) {
+ add_guard_point (when - 64);
+ }
+ maybe_add_insert_guard (when);
+ }
+
+ 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) {
+ return false;
+ }
+
+ mark_dirty ();
+ maybe_signal_changed ();
+
+ return true;
+}
+
+void
+ControlList::maybe_add_insert_guard (double when)
+{
+ if (most_recent_insert_iterator != _events.end()) {
+ if ((*most_recent_insert_iterator)->when - when > 64) {
+ /* Next control point is some distance from where our new point is
+ going to go, so add a new point to avoid changing the shape of
+ the line too much. The insert iterator needs to point to the
+ new control point so that our insert will happen correctly. */
+ most_recent_insert_iterator = _events.insert (
+ most_recent_insert_iterator,
+ new ControlEvent (when + 64, (*most_recent_insert_iterator)->value));
+ DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added insert guard point @ %2 = %3\n",
+ this, when + 64,
+ (*most_recent_insert_iterator)->value));
+ }
+ }
+}
+
+/** If we would just be adding to a straight line, move the previous point instead. */
+bool
+ControlList::maybe_insert_straight_line (double when, double value)
+{
+ if (_events.empty()) {
+ return false;
+ }
+
+ if (_events.back()->value == value) {
+ // Point b at the final point, which we know exists
+ EventList::iterator b = _events.end();
+ --b;
+ if (b == _events.begin()) {
+ return false; // No previous point
+ }
+
+ // Check the previous point's value
+ --b;
+ if ((*b)->value == value) {
+ /* At least two points with the exact same value (straight
+ line), just move the final point to the new time. */
+ _events.back()->when = when;
+ DEBUG_TRACE (DEBUG::ControlList, string_compose ("final value of %1 moved to %2\n", value, when));
+ return true;
+ }
+ }
+ return false;
+}
+
+ControlList::iterator
+ControlList::erase_from_iterator_to (iterator iter, double when)
+{
+ while (iter != _events.end()) {
+ if ((*iter)->when < when) {
+ DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 erase existing @ %2\n", this, (*iter)->when));
+ delete *iter;
+ iter = _events.erase (iter);
+ continue;
+ } else if ((*iter)->when >= when) {
+ break;
+ }
+ ++iter;
+ }
+ return iter;
+}
+