Skip to content

Commit 0dbdf38

Browse files
authored
Merge pull request #7 from daschuer/beatloop_size
Removing Random jump into Loop when qantisation is enabeled.
2 parents 9bd5ff8 + 50546a4 commit 0dbdf38

4 files changed

Lines changed: 61 additions & 54 deletions

File tree

src/engine/bpmcontrol.cpp

Lines changed: 55 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ double BpmControl::calcSyncedRate(double userTweak) {
400400

401401
// Now that we have our beat distance we can also check how large the
402402
// current loop is. If we are in a <1 beat loop, don't worry about offset.
403-
const bool loop_enabled = m_pLoopEnabled->get() > 0.0;
403+
const bool loop_enabled = m_pLoopEnabled->toBool();
404404
const double loop_size = (m_pLoopEndPosition->get() -
405405
m_pLoopStartPosition->get()) /
406406
dBeatLength;
@@ -567,14 +567,14 @@ bool BpmControl::getBeatContextNoLookup(
567567
return true;
568568
}
569569

570-
double BpmControl::getPhaseOffset(double dThisPosition) {
570+
double BpmControl::getNearestPositionInPhase(double dThisPosition, bool respectLoops) {
571571
// Without a beatgrid, we don't know the phase offset.
572572
if (!m_pBeats) {
573-
return 0;
573+
return dThisPosition;
574574
}
575575
// Master buffer is always in sync!
576576
if (getSyncMode() == SYNC_MASTER) {
577-
return 0;
577+
return dThisPosition;
578578
}
579579

580580
// Get the current position of this deck.
@@ -588,13 +588,13 @@ double BpmControl::getPhaseOffset(double dThisPosition) {
588588
if (!getBeatContext(m_pBeats, dThisPosition,
589589
&dThisPrevBeat, &dThisNextBeat,
590590
&dThisBeatLength, NULL)) {
591-
return 0;
591+
return dThisPosition;
592592
}
593593
} else {
594594
if (!getBeatContextNoLookup(dThisPosition,
595595
dThisPrevBeat, dThisNextBeat,
596596
&dThisBeatLength, NULL)) {
597-
return 0;
597+
return dThisPosition;
598598
}
599599
}
600600

@@ -606,15 +606,15 @@ double BpmControl::getPhaseOffset(double dThisPosition) {
606606
// If not, we have to figure it out
607607
EngineBuffer* pOtherEngineBuffer = pickSyncTarget();
608608
if (pOtherEngineBuffer == NULL) {
609-
return 0;
609+
return dThisPosition;
610610
}
611611

612612
TrackPointer otherTrack = pOtherEngineBuffer->getLoadedTrack();
613613
BeatsPointer otherBeats = otherTrack ? otherTrack->getBeats() : BeatsPointer();
614614

615615
// If either track does not have beats, then we can't adjust the phase.
616616
if (!otherBeats) {
617-
return 0;
617+
return dThisPosition;
618618
}
619619

620620
double dOtherLength = ControlObject::getControl(
@@ -624,7 +624,7 @@ double BpmControl::getPhaseOffset(double dThisPosition) {
624624

625625
if (!BpmControl::getBeatContext(otherBeats, dOtherPosition,
626626
NULL, NULL, NULL, &dOtherBeatFraction)) {
627-
return 0.0;
627+
return dThisPosition;
628628
}
629629
}
630630

@@ -658,51 +658,55 @@ double BpmControl::getPhaseOffset(double dThisPosition) {
658658
dNewPlaypos += dThisPrevBeat;
659659
}
660660

661-
// We might be seeking outside the loop.
662-
const bool loop_enabled = m_pLoopEnabled->get() > 0.0;
663-
const double loop_start_position = m_pLoopStartPosition->get();
664-
const double loop_end_position = m_pLoopEndPosition->get();
665-
666-
// Cases for sanity:
667-
//
668-
// CASE 1
669-
// Two identical 1-beat loops, out of phase by X samples.
670-
// Other deck is at its loop start.
671-
// This deck is half way through. We want to jump forward X samples to the loop end point.
672-
//
673-
// Two identical 1-beat loop, out of phase by X samples.
674-
// Other deck is
675-
676-
// If sync target is 50% through the beat,
677-
// If we are at the loop end point and hit sync, jump forward X samples.
678-
679-
680-
// TODO(rryan): Revise this with something that keeps a broader number of
681-
// cases in sync. This at least prevents breaking out of the loop.
682-
if (loop_enabled) {
683-
const double loop_length = loop_end_position - loop_start_position;
684-
if (loop_length <= 0.0) {
685-
return false;
686-
}
687-
688-
// TODO(rryan): If loop_length is not a multiple of dThisBeatLength should
689-
// we bail and not sync phase?
690-
691-
// Syncing to after the loop end.
692-
double end_delta = dNewPlaypos - loop_end_position;
693-
if (end_delta > 0) {
694-
int i = end_delta / loop_length;
695-
dNewPlaypos = loop_start_position + end_delta - i * loop_length;
696-
}
697-
698-
// Syncing to before the loop beginning.
699-
double start_delta = loop_start_position - dNewPlaypos;
700-
if (start_delta > 0) {
701-
int i = start_delta / loop_length;
702-
dNewPlaypos = loop_end_position - start_delta + i * loop_length;
661+
if (respectLoops) {
662+
// We might be seeking outside the loop.
663+
const bool loop_enabled = m_pLoopEnabled->toBool();
664+
const double loop_start_position = m_pLoopStartPosition->get();
665+
const double loop_end_position = m_pLoopEndPosition->get();
666+
667+
// Cases for sanity:
668+
//
669+
// CASE 1
670+
// Two identical 1-beat loops, out of phase by X samples.
671+
// Other deck is at its loop start.
672+
// This deck is half way through. We want to jump forward X samples to the loop end point.
673+
//
674+
// Two identical 1-beat loop, out of phase by X samples.
675+
// Other deck is
676+
677+
// If sync target is 50% through the beat,
678+
// If we are at the loop end point and hit sync, jump forward X samples.
679+
680+
681+
// TODO(rryan): Revise this with something that keeps a broader number of
682+
// cases in sync. This at least prevents breaking out of the loop.
683+
if (loop_enabled &&
684+
dThisPosition <= loop_end_position) {
685+
const double loop_length = loop_end_position - loop_start_position;
686+
const double end_delta = dNewPlaypos - loop_end_position;
687+
688+
// Syncing to after the loop end.
689+
if (end_delta > 0 && loop_length > 0.0) {
690+
int i = end_delta / loop_length;
691+
dNewPlaypos = loop_start_position + end_delta - i * loop_length;
692+
693+
// Move new position after loop jump into phase as well.
694+
// This is a recursive call, called only twice because of
695+
// respectLoops = false
696+
dNewPlaypos = getNearestPositionInPhase(dNewPlaypos, false);
697+
}
698+
699+
// Note: Syncing to before the loop beginning is allowed, because
700+
// loops are catching
703701
}
704702
}
705703

704+
return dNewPlaypos;
705+
}
706+
707+
double BpmControl::getPhaseOffset(double dThisPosition) {
708+
// This does not respect looping
709+
double dNewPlaypos = getNearestPositionInPhase(dThisPosition, false);
706710
return dNewPlaypos - dThisPosition;
707711
}
708712

src/engine/bpmcontrol.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ class BpmControl : public EngineControl {
3333
// out of sync.
3434
double calcSyncedRate(double userTweak);
3535
// Get the phase offset from the specified position.
36-
double getPhaseOffset(double reference_position);
36+
double getNearestPositionInPhase(double dThisPosition, bool respectLoops = true);
37+
double getPhaseOffset(double dThisPosition);
3738
double getBeatDistance(double dThisPosition) const;
3839
double getPreviousSample() const { return m_dPreviousSample; }
3940

src/engine/enginebuffer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1165,7 +1165,7 @@ void EngineBuffer::processSeek(bool paused) {
11651165
}
11661166

11671167
if ((seekType & SEEK_PHASE) && !paused && m_pQuantize->toBool()) {
1168-
position += m_pBpmControl->getPhaseOffset(position);
1168+
position = m_pBpmControl->getNearestPositionInPhase(position);
11691169
}
11701170

11711171
double newPlayFrame = position / kSamplesPerFrame;

src/engine/loopingcontrol.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,9 @@ void LoopingControl::slotLoopEndPos(double pos) {
739739
void LoopingControl::notifySeek(double dNewPlaypos) {
740740
LoopSamples loopSamples = m_loopSamples.getValue();
741741
if (m_bLoopingEnabled) {
742-
if (dNewPlaypos < loopSamples.start || dNewPlaypos > loopSamples.end) {
742+
// Disable loop when we jump after it, using hot cues or waveform overview
743+
// If we jump before, the loop it is kept enabled as catching loop
744+
if (dNewPlaypos > loopSamples.end) {
743745
setLoopingEnabled(false);
744746
}
745747
}

0 commit comments

Comments
 (0)