diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 3068c4492b77..19c506e086cf 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -5,11 +5,12 @@ #include #include "control/controlobject.h" -#include "preferences/usersettings.h" #include "control/controlpushbutton.h" -#include "engine/controls/loopingcontrol.h" #include "engine/controls/bpmcontrol.h" #include "engine/controls/enginecontrol.h" +#include "engine/controls/loopingcontrol.h" +#include "engine/enginebuffer.h" +#include "preferences/usersettings.h" #include "util/compatibility.h" #include "util/math.h" #include "util/sample.h" @@ -478,6 +479,11 @@ double LoopingControl::getSyncPositionInsideLoop(double dRequestedPlaypos, doubl // prevents jumping in front of the loop if loop is smaller than adjustment adjustment = fmod(adjustment, loopSize); + // if the synced position is exactly the start of the loop we would end up at the exact end + // as this would disable the loop in notifySeek() replace it with the start of the loop + if (adjustment == 0) { + return loopSamples.start; + } return loopSamples.end - adjustment; } @@ -818,7 +824,7 @@ void LoopingControl::notifySeek(double dNewPlaypos) { if (m_bLoopingEnabled) { // Disable loop when we jumping out, or over a catching loop, // using hot cues or waveform overview. - // Do not jump out of a loop if we adjust a phase (lp1743010) + // Jumping to the exact end of a loop is considered jumping out. if (currentSample >= loopSamples.start && currentSample <= loopSamples.end && dNewPlaypos < loopSamples.start) { @@ -826,8 +832,8 @@ void LoopingControl::notifySeek(double dNewPlaypos) { setLoopingEnabled(false); } if (currentSample <= loopSamples.end && - dNewPlaypos > loopSamples.end) { - // jumping out a loop or over a catching loop forward + dNewPlaypos >= loopSamples.end) { + // jumping out or to the exact end of a loop or over a catching loop forward setLoopingEnabled(false); } } @@ -1002,6 +1008,13 @@ void LoopingControl::updateBeatLoopingControls() { } void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable) { + // if a seek was queued in the engine buffer move the current sample to its position + double p_seekPosition = 0; + if (getEngineBuffer()->getQueuedSeekPosition(&p_seekPosition)) { + // seek position is already quantized if quantization is enabled + m_currentSample.setValue(p_seekPosition); + } + double maxBeatSize = s_dBeatSizes[sizeof(s_dBeatSizes)/sizeof(s_dBeatSizes[0]) - 1]; double minBeatSize = s_dBeatSizes[0]; if (beats < 0) { diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index 030c150b7f47..2c10c3bfe8a4 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -1125,7 +1125,8 @@ void EngineBuffer::processSeek(bool paused) { // call anyway again. SeekRequests seekType = static_cast( - m_iSeekQueued.fetchAndStoreRelease(SEEK_NONE)); + m_iSeekQueued.loadAcquire()); + double position = m_queuedSeekPosition.getValue(); // Don't allow the playposition to go past the end. @@ -1169,6 +1170,7 @@ void EngineBuffer::processSeek(bool paused) { if (position != m_filepos_play) { setNewPlaypos(position); } + m_iSeekQueued.storeRelease(SEEK_NONE); } void EngineBuffer::postProcess(const int iBufferSize) { @@ -1284,6 +1286,16 @@ bool EngineBuffer::isTrackLoaded() { return false; } +bool EngineBuffer::getQueuedSeekPosition(double* pSeekPosition) { + bool isSeekQueued = m_iSeekQueued.loadAcquire() != SEEK_NONE; + if (isSeekQueued) { + *pSeekPosition = m_queuedSeekPosition.getValue(); + } else { + *pSeekPosition = -1; + } + return isSeekQueued; +} + void EngineBuffer::slotEjectTrack(double v) { if (v > 0) { // Don't allow rejections while playing a track. We don't need to lock to diff --git a/src/engine/enginebuffer.h b/src/engine/enginebuffer.h index 6baaa85fa31e..46735d16fa11 100644 --- a/src/engine/enginebuffer.h +++ b/src/engine/enginebuffer.h @@ -141,6 +141,9 @@ class EngineBuffer : public EngineObject { QString getGroup(); bool isTrackLoaded(); + // return true if a seek is currently cueued but not yet processed, false otherwise + // if no seek was queued, the seek position is set to -1 + bool getQueuedSeekPosition(double* pSeekPosition); TrackPointer getLoadedTrack() const; double getExactPlayPos();