Skip to content

Commit 4144a35

Browse files
committed
Suppress loop-record playhead setup when cursor sits past loop end
performPlay already treats cursor-past-loop as a non-looping session (matches the user's expectation that playback continues forward without jumping back to a loop region the cursor has already passed). performRecord was missing the equivalent: it called setLoopTimes(true, lr) and setRollInToLoop(prerollStart) unconditionally on looping=true, and PlayHead::setRollInToLoop clamps positions to loopEnd, so a record start with the cursor past the loop ended up rolling at the loop boundary instead of the cursor. Compute effectivelyLooping the same way performPlay does, and use it to gate the looped playhead branch.
1 parent b60b9be commit 4144a35

1 file changed

Lines changed: 14 additions & 1 deletion

File tree

modules/tracktion_engine/playback/tracktion_TransportControl.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1477,6 +1477,14 @@ std::optional<std::pair<SyncPoint, std::optional<TimeRange>>> TransportControl::
14771477
transportState->startTime = position.get();
14781478
transportState->endTime = Edit::getMaximumEditEnd();
14791479

1480+
// MAGDA patch: mirror performPlay's cursor-vs-loop policy. If the cursor sits
1481+
// past the loop end at record start, treat this session as non-looping so the
1482+
// playhead doesn't snap-clamp back to the loop region. Looping re-engages on
1483+
// the next start whenever the cursor is back in or before the region.
1484+
const bool cursorPastLoop = looping
1485+
&& transportState->startTime.get() > loopRange.getEnd() - 0.1s;
1486+
const bool effectivelyLooping = looping && ! cursorPastLoop;
1487+
14801488
if (looping)
14811489
{
14821490
if (loopRange.getLength() < 2s)
@@ -1495,6 +1503,11 @@ std::optional<std::pair<SyncPoint, std::optional<TimeRange>>> TransportControl::
14951503
// startTime stays at the cursor position set above (line ~1477). Pre-roll /
14961504
// count-in continues to back up from cursor, and the existing setRollInToLoop
14971505
// call further down handles the cursor-before-loop case naturally.
1506+
if (cursorPastLoop)
1507+
{
1508+
// Cursor is past the loop end — record forward without looping this session.
1509+
// transportState->endTime already equals Edit::getMaximumEditEnd() from above.
1510+
}
14981511
}
14991512
else if (edit.recordingPunchInOut)
15001513
{
@@ -1542,7 +1555,7 @@ std::optional<std::pair<SyncPoint, std::optional<TimeRange>>> TransportControl::
15421555
if (edit.getNumCountInBeats() > 0)
15431556
playHeadWrapper->setLoopTimes (true, { transportState->startTime.get(), Edit::getMaximumEditEnd() });
15441557

1545-
if (looping)
1558+
if (effectivelyLooping)
15461559
{
15471560
// The order of this is critical as the audio thread might jump in and reset the
15481561
// roll-in-to-loop status of the loop-range is not set first

0 commit comments

Comments
 (0)