From 2de84c97d0a2abde6602518c182eed6a208c79aa Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Fri, 15 Jul 2022 19:54:21 +0200 Subject: [PATCH] Fix Temporal::Range::squish reduced to samples Loop Location start="a1665678660" end="b145920" Loop-end (at 122BPM) is a2109859636 at 48kHz this is sample 1794098.32 Now play the loop and play sample 1794098 = a2109859248 Range::squish start: a1665678660 end: a2109859636 squish: a2109859248 squish() does nothing, since there are still 388 superclock-ticks until the end of the loop. However, DiskReader::get_midi_playback convertes the value back to samples(), this leads to effective_start == loop_end; resulting in an endless loop. Thanks to MikeLupe to provide a session to reproduce this issue. --- libs/ardour/disk_reader.cc | 9 +++++++-- libs/temporal/temporal/range.h | 6 ++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/libs/ardour/disk_reader.cc b/libs/ardour/disk_reader.cc index 7039c84b1b..c5f984833e 100644 --- a/libs/ardour/disk_reader.cc +++ b/libs/ardour/disk_reader.cc @@ -1466,8 +1466,13 @@ DiskReader::get_midi_playback (MidiBuffer& dst, samplepos_t start_sample, sample Location* loc = _loop_location; if (loc) { - /* Evoral::Range has inclusive range semantics. Ugh. Hence the -1 */ - const Temporal::Range loop_range (loc->start (), loc->end ()); + /* squish() operates in the location's time-domain. When the location was created + * using music-time, and later converted to audio-time, it can happen that the + * corresponding super-clock is "between samples". e.g loop-end is at sample 1000.12. + * if start_sample = 1000; squish() does nothing because 1000 < 1000.12. + * This is solved by creating the range using (rounded) sample-times. + */ + const Temporal::Range loop_range (loc->start ().samples(), loc->end ().samples()); samplepos_t effective_start = start_sample; samplecnt_t cnt = nframes; sampleoffset_t offset = 0; diff --git a/libs/temporal/temporal/range.h b/libs/temporal/temporal/range.h index cce5dd7b73..d9873ccc9a 100644 --- a/libs/temporal/temporal/range.h +++ b/libs/temporal/temporal/range.h @@ -150,6 +150,7 @@ class LIBTEMPORAL_API Range { */ Range (timepos_t const & s, timepos_t const & e) : _start (s), _end (e) {} + Range (samplepos_t const s, samplepos_t const e) : _start (s), _end (e) {} bool empty() const { return _start == _end; } timecnt_t length() const { return _start.distance (_end); } @@ -165,6 +166,11 @@ class LIBTEMPORAL_API Range { return other._start == _start && other._end == _end; } + void force_to_samples () { + _start = timepos_t((samplepos_t)_start.samples ()); + _end = timepos_t((samplepos_t)_end.samples ()); + } + /** for a T, return a mapping of it into the range (used for * looping). If the argument is earlier than or equal to the end of * this range, do nothing.