Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Beatloops snap to the closest (fractional) beat in quantized mode LP1752133 #2286

Merged
merged 3 commits into from
Sep 27, 2019
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
45 changes: 33 additions & 12 deletions src/engine/controls/loopingcontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ LoopingControl::LoopingControl(QString group,
m_loopSamples.setValue(m_oldLoopSamples);
m_currentSample.setValue(0.0);
m_pActiveBeatLoop = NULL;

m_pRateControl = NULL;
//Create loop-in, loop-out, loop-exit, and reloop/exit ControlObjects
m_pLoopInButton = new ControlPushButton(ConfigKey(group, "loop_in"));
connect(m_pLoopInButton, &ControlObject::valueChanged,
Expand Down Expand Up @@ -682,6 +682,10 @@ void LoopingControl::setLoopOutToCurrentPosition() {
m_loopSamples.setValue(loopSamples);
}

void LoopingControl::setRateControl(RateControl* rateControl) {
m_pRateControl = rateControl;
}

void LoopingControl::slotLoopOut(double pressed) {
if (m_pTrack == nullptr) {
return;
Expand Down Expand Up @@ -1060,16 +1064,19 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable
newloopSamples.start = currentSample;
}
} else {
// loop_in is set to the previous beat if quantize is on. The
// closest beat might be ahead of play position which would cause a seek.
// TODO: If in reverse, should probably choose nextBeat.
// loop_in is set to the closest beat if quantize is on and the loop size is >= 1 beat.
// The closest beat might be ahead of play position and will cause a catching loop.
double prevBeat;
double nextBeat;
pBeats->findPrevNextBeats(currentSample, &prevBeat, &nextBeat);

if (m_pQuantizeEnabled->toBool() && prevBeat != -1) {
double beatLength = nextBeat - prevBeat;
double loopLength = beatLength * beats;

double closestBeat = pBeats->findClosestBeat(currentSample);
if (beats >= 1.0) {
newloopSamples.start = prevBeat;
newloopSamples.start = closestBeat;
} else {
// In case of beat length less then 1 beat:
// (| - beats, ^ - current track's position):
Expand All @@ -1078,15 +1085,29 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable
//
// If we press 1/2 beatloop we want loop from 50% to 100%,
// If I press 1/4 beatloop, we want loop from 50% to 75% etc
double beat_len = nextBeat - prevBeat;
double loops_per_beat = 1.0 / beats;
double beat_pos = currentSample - prevBeat;
int beat_frac =
static_cast<int>(floor((beat_pos / beat_len) *
loops_per_beat));
newloopSamples.start = prevBeat + beat_len / loops_per_beat * beat_frac;
double samplesSinceLastBeat = currentSample - prevBeat;

// find the previous beat fraction and check if the current position is closer to this or the next one
// place the new loop start to the closer one
double previousFractionBeat = prevBeat + floor(samplesSinceLastBeat / loopLength) * loopLength;
double samplesSinceLastFractionBeat = currentSample - previousFractionBeat;

if (samplesSinceLastFractionBeat <= (loopLength / 2.0)) {
newloopSamples.start = previousFractionBeat;
} else {
newloopSamples.start = previousFractionBeat + loopLength;
}
}

// If running reverse, move the loop one loop size to the left.
// Thus, the loops end will be closest to the current position
bool reverse = false;
if (m_pRateControl != NULL) {
reverse = m_pRateControl->isReverseButtonPressed();
}
if (reverse) {
newloopSamples.start -= loopLength;
}
} else {
newloopSamples.start = currentSample;
}
Expand Down
10 changes: 6 additions & 4 deletions src/engine/controls/loopingcontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
#include <QObject>
#include <QStack>

#include "preferences/usersettings.h"
#include "control/controlvalue.h"
#include "engine/controls/enginecontrol.h"
#include "track/track.h"
#include "engine/controls/ratecontrol.h"
#include "preferences/usersettings.h"
#include "track/beats.h"
#include "control/controlvalue.h"
#include "track/track.h"

#define MINIMUM_AUDIBLE_LOOP_SIZE 300 // In samples

Expand Down Expand Up @@ -50,7 +51,7 @@ class LoopingControl : public EngineControl {
double getSyncPositionInsideLoop(double dRequestedPlaypos, double dSyncedPlayPos);

void notifySeek(double dNewPlaypos) override;

void setRateControl(RateControl* rateControl);
bool isLoopingEnabled();

public slots:
Expand Down Expand Up @@ -129,6 +130,7 @@ class LoopingControl : public EngineControl {
ControlPushButton* m_pLoopHalveButton;
ControlPushButton* m_pLoopDoubleButton;
ControlObject* m_pSlipEnabled;
RateControl* m_pRateControl;
ControlObject* m_pPlayButton;

bool m_bLoopingEnabled;
Expand Down
7 changes: 7 additions & 0 deletions src/engine/controls/ratecontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -556,3 +556,10 @@ void RateControl::resetRateTemp(void)
void RateControl::notifySeek(double playPos) {
m_pScratchController->notifySeek(playPos);
}

bool RateControl::isReverseButtonPressed() {
if (m_pReverseButton) {
return m_pReverseButton->toBool();
}
return false;
}
1 change: 1 addition & 0 deletions src/engine/controls/ratecontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class RateControl : public EngineControl {
static void setRateRampSensitivity(int);
static int getRateRampSensitivity();
void notifySeek(double dNewPlaypos) override;
bool isReverseButtonPressed();

public slots:
void slotReverseRollActivate(double);
Expand Down
12 changes: 9 additions & 3 deletions src/engine/enginebuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,14 +180,13 @@ EngineBuffer::EngineBuffer(const QString& group, UserSettingsPointer pConfig,
// quantization (alignment) of loop in/out positions and (hot)cues with
// beats.
QuantizeControl* quantize_control = new QuantizeControl(group, pConfig);
addControl(quantize_control);
m_pQuantize = ControlObject::getControl(ConfigKey(group, "quantize"));

// Create the Loop Controller
m_pLoopingControl = new LoopingControl(group, pConfig);
addControl(m_pLoopingControl);

addControl(quantize_control);
m_pQuantize = ControlObject::getControl(ConfigKey(group, "quantize"));

m_pEngineSync = pMixingEngine->getEngineSync();

m_pSyncControl = new SyncControl(group, pConfig, pChannel, m_pEngineSync);
Expand All @@ -198,9 +197,12 @@ EngineBuffer::EngineBuffer(const QString& group, UserSettingsPointer pConfig,
addControl(m_pVinylControlControl);
#endif

// Create the Rate Controller
m_pRateControl = new RateControl(group, pConfig);
// Add the Rate Controller
addControl(m_pRateControl);
// Looping Control needs Rate Control for Reverse Button
m_pLoopingControl->setRateControl(m_pRateControl);

// Create the BPM Controller
m_pBpmControl = new BpmControl(group, pConfig);
Expand Down Expand Up @@ -532,6 +534,10 @@ TrackPointer EngineBuffer::getLoadedTrack() const {
return m_pCurrentTrack;
}

bool EngineBuffer::isReverse() {
return m_reverse_old;
}

void EngineBuffer::ejectTrack() {
// clear track values in any case, this may fix Bug #1450424
//qDebug() << "EngineBuffer::ejectTrack()";
Expand Down
2 changes: 2 additions & 0 deletions src/engine/enginebuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ class EngineBuffer : public EngineObject {
bool getQueuedSeekPosition(double* pSeekPosition);
TrackPointer getLoadedTrack() const;

bool isReverse();

double getExactPlayPos();
double getVisualPlayPos();
double getTrackSamples();
Expand Down