Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 38 additions & 13 deletions src/engine/controls/loopingcontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,15 @@ void LoopingControl::slotBeatLoopDeactivate(BeatLoopingControl* pBeatLoopControl

void LoopingControl::slotBeatLoopDeactivateRoll(BeatLoopingControl* pBeatLoopControl) {
pBeatLoopControl->deactivate();

if (!m_bLoopRollActive) {
// beatloop_activate was pressed while rolling and slotBeatLoopToggle()
// did already reset roll status (m_activeLoopRolls, m_bLoopRollActive)
// and EngineBuffer quit slip mode (but didn't seek).
// So nothing to do here, just leave the adopted loop active.
return;
}

const double size = pBeatLoopControl->getSize();
// clang-tidy wants auto to be auto* because QStack inherits from QVector
// and QVector::iterator is a pointer type in Qt5, but QStack inherits
Expand All @@ -1325,18 +1334,15 @@ void LoopingControl::slotBeatLoopDeactivateRoll(BeatLoopingControl* pBeatLoopCon

// Make sure slip mode is not turned off if it was turned on
// by something that was not a rolling beatloop.
if (m_bLoopRollActive && m_activeLoopRolls.empty()) {
if (m_activeLoopRolls.empty()) {
setLoopingEnabled(false);
m_pSlipEnabled->set(0);
m_bLoopRollActive = false;
}

// Return to the previous beatlooproll if necessary.
// Else previous regular beatloop if no rolling loops are active.
if (!m_activeLoopRolls.empty()) {
slotBeatLoop(m_activeLoopRolls.top(), m_bLoopRollActive, true);
} else {
restoreLoopInfo();
} else {
// Return to the previous beatlooproll if necessary.
// Else previous regular beatloop if no rolling loops are active.
slotBeatLoop(m_activeLoopRolls.top(), m_bLoopRollActive, true);
}
}

Expand Down Expand Up @@ -1694,14 +1700,25 @@ void LoopingControl::slotBeatLoopSizeChangeRequest(double beats) {
}

void LoopingControl::slotBeatLoopToggle(double pressed) {
if (pressed > 0) {
if (m_bLoopingEnabled) {
if (pressed <= 0) {
return;
}

if (m_bLoopingEnabled) {
// If we're in a rolling loop, quit slip mode and adopt it as regular loop.
// Use case is to have a looproll button pressed, then press loop_activate
// and nothing should happen when releasing the looproll button.
if (m_bLoopRollActive) {
m_bLoopRollActive = false;
m_activeLoopRolls.clear();
getEngineBuffer()->slipQuitAndAdopt();
} else {
// Deactivate the loop if we're already looping
setLoopingEnabled(false);
} else {
// Create a loop at current position
slotBeatLoop(m_pCOBeatLoopSize->get());
}
} else {
// Create a loop at current position
slotBeatLoop(m_pCOBeatLoopSize->get());
}
}

Expand All @@ -1723,6 +1740,14 @@ void LoopingControl::slotBeatLoopRollActivate(double pressed) {
m_bLoopRollActive = true;
}
} else {
if (!m_bLoopRollActive) {
// beatloop_activate was pressed while rolling and slotBeatLoopToggle()
// did already reset roll status (m_activeLoopRolls, m_bLoopRollActive)
// and EngineBuffer quit slip mode (but didn't seek).
// So nothing to do here, just leave the adopted loop active.
return;
}

setLoopingEnabled(false);
// Make sure slip mode is not turned off if it was turned on
// by something that was not a rolling beatloop.
Expand Down
14 changes: 12 additions & 2 deletions src/engine/enginebuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ EngineBuffer::EngineBuffer(const QString& group,
m_iSeekPhaseQueued(0),
m_iEnableSyncQueued(SYNC_REQUEST_NONE),
m_iSyncModeQueued(static_cast<int>(SyncMode::Invalid)),
m_slipQuitAndAdopt(0),
m_bPlayAfterLoading(false),
m_channelCount(mixxx::kEngineChannelOutputCount),
m_pCrossfadeBuffer(SampleUtil::alloc(
Expand Down Expand Up @@ -864,6 +865,11 @@ void EngineBuffer::slotKeylockEngineChanged(double dIndex) {
}
}

void EngineBuffer::slipQuitAndAdopt() {
m_slipQuitAndAdopt.storeRelease(1);
m_pSlipButton->set(0);
}

void EngineBuffer::processTrackLocked(
CSAMPLE* pOutput, const std::size_t bufferSize, mixxx::audio::SampleRate sampleRate) {
ScopedTimer t(QStringLiteral("EngineBuffer::process_pauselock"));
Expand Down Expand Up @@ -1257,8 +1263,12 @@ void EngineBuffer::processSlip(std::size_t bufferSize) {
m_slipPos = m_playPos;
m_dSlipRate = m_rate_old;
} else {
// TODO(owen) assuming that looping will get canceled properly
seekExact(m_slipPos.toNearestFrameBoundary());
// If m_slipQuitAndAdopt is 1 we've already quit slip mode
// but we don't seek in that case.
if (m_slipQuitAndAdopt.fetchAndStoreAcquire(0) == 0) {
// TODO(owen) assuming that looping will get canceled properly
seekExact(m_slipPos.toNearestFrameBoundary());
}
m_slipPos = mixxx::audio::kStartFramePos;
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/engine/enginebuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ class EngineBuffer : public EngineObject {

void verifyPlay();

void slipQuitAndAdopt();

public slots:
void slotControlPlayRequest(double);
void slotControlPlayFromStart(double);
Expand Down Expand Up @@ -466,6 +468,7 @@ class EngineBuffer : public EngineObject {
ControlValueAtomic<QueuedSeek> m_queuedSeek;
bool m_previousBufferSeek = false;

QAtomicInt m_slipQuitAndAdopt;
/// Indicates that no seek is queued
static constexpr QueuedSeek kNoQueuedSeek = {mixxx::audio::kInvalidFramePos, SEEK_NONE};
/// indicates a clone seek on a bosition from another deck
Expand Down