From b5f1c5b0dd1f7060aef5235a1b0ed8c488ff6d1c Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 7 Aug 2025 12:26:12 -0600 Subject: [PATCH] Fix potential infinite loop when iterating over ControlLists If you have the "wrong" kind of MIDI CC, the interpolation for the list is set to Linear, which causes interpolation to return audio time stamps instead of beat time. Because of the asymmetrical transforms, this causes iterators over the Sequence to go haywire and create an infinite loop. This fix changes ControlList behavior to always return times in the time domain of the list. --- libs/evoral/ControlList.cc | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/libs/evoral/ControlList.cc b/libs/evoral/ControlList.cc index b6ec83b3ad..6ef47917b0 100644 --- a/libs/evoral/ControlList.cc +++ b/libs/evoral/ControlList.cc @@ -1883,20 +1883,33 @@ ControlList::rt_safe_earliest_event_linear_unlocked (Temporal::timepos_t const& } /* This method is ONLY used for interpolating to generate value/time - * duples not present in the actual ControlList, and because of this, - * the desired time domain is always audio time. + * duples not present in the actual ControlList */ - double a = first->when.superclocks (); - double b = next->when.superclocks (); - const double slope = (b - a) / (next->value - first->value); - assert (slope != 0); + double slope; + + if (time_domain() == Temporal::AudioTime) { + double a = first->when.superclocks (); + double b = next->when.superclocks (); + slope = (b - a) / (next->value - first->value); + assert (slope != 0); + double t = start_time.superclocks (); + double dt = fmod (t, fabs (slope)); + t += fabs (slope) - dt; + x = timecnt_t::from_superclock (t + 1); + y = rint (first->value + (t - a) / slope); + } else { + double a = first->when.beats().to_ticks(); + double b = next->when.beats().to_ticks(); + slope = (b - a) / (next->value - first->value); + assert (slope != 0); + double t = start_time.beats ().to_ticks(); + double dt = fmod (t, fabs (slope)); + t += fabs (slope) - dt; + x = timecnt_t::from_ticks (t + 1); + y = rint (first->value + (t - a) / slope); + } - double t = start_time.superclocks (); - double dt = fmod (t, fabs (slope)); - t += fabs (slope) - dt; - x = timecnt_t::from_superclock (t + 1); - y = rint (first->value + (t - a) / slope); if (slope > 0) { y = std::max (first->value, std::min (next->value, y)); } else {