+ /* If we see the end of a loop during this read, we must write the events after it
+ to the MidiBuffer with adjusted times. The situation is as follows:
+
+ session frames----------------------------->
+
+ | | |
+ start_of_loop start end_of_loop
+
+ The MidiDiskstream::read method which will have happened before this checks for
+ loops ending, and helpfully inserts a magic LoopEvent into the ringbuffer. After this,
+ the MidiDiskstream continues to write events with their proper session frame times,
+ so after the LoopEvent event times will go backwards (ie non-monotonically).
+
+ Once we hit end_of_loop, we need to fake it to make it look as though the loop has been
+ immediately repeated. Say that an event E after the end_of_loop in the ringbuffer
+ has time E_t, which is a time in session frames. Its offset from the start
+ of the loop will be E_t - start_of_loop. Its `faked' time will therefore be
+ end_of_loop + E_t - start_of_loop. And so its port-buffer-relative time (for
+ writing to the MidiBuffer) will be end_of_loop + E_t - start_of_loop - start.
+
+ The subtraction of start is already taken care of, so if we see a LoopEvent, we'll
+ set up loop_offset to equal end_of_loop - start_of_loop, so that given an event
+ time E_t in the ringbuffer we can get the port-buffer-relative time as
+ E_t + offset - start.
+ */
+
+ frameoffset_t loop_offset = 0;
+