Skip to content

Commit

Permalink
repeat: after last sample, fill buffer with samples from track start
Browse files Browse the repository at this point in the history
or with samples from end, if playing in reverse.

Previously, the last buffer at track end was padded with silence which makes the track longer than
it actually is, then seeked to track start. With loop tracks (length is exactly n beats) this caused
beat offsets.
  • Loading branch information
ronso0 committed May 5, 2023
1 parent 2b15819 commit 7c55f3e
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 23 deletions.
14 changes: 14 additions & 0 deletions src/engine/controls/loopingcontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ LoopingControl::LoopingControl(const QString& group,
this, &LoopingControl::slotLoopDouble);

m_pPlayButton = ControlObject::getControl(ConfigKey(group, "play"));

m_pRepeatButton = ControlObject::getControl(ConfigKey(group, "repeat"));
}

LoopingControl::~LoopingControl() {
Expand Down Expand Up @@ -423,6 +425,18 @@ double LoopingControl::nextTrigger(bool reverse,
return loopSamples.end;
}
}

// Return trigger if repeat is enabled
if (m_pRepeatButton->toBool()) {
if (reverse) {
*pTarget = m_pTrackSamples->get();
return 0.0;
} else {
*pTarget = 0.0;
return m_pTrackSamples->get();
}
}

return kNoTrigger;
}

Expand Down
1 change: 1 addition & 0 deletions src/engine/controls/loopingcontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ class LoopingControl : public EngineControl {
ControlObject* m_pSlipEnabled;
RateControl* m_pRateControl;
ControlObject* m_pPlayButton;
ControlObject* m_pRepeatButton;

bool m_bLoopingEnabled;
bool m_bLoopRollActive;
Expand Down
41 changes: 22 additions & 19 deletions src/engine/enginebuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,6 @@ EngineBuffer::EngineBuffer(const QString& group,
pMixingEngine->getEngineSync()->addSyncableDeck(m_pSyncControl);
addControl(m_pSyncControl);

m_fwdButton = ControlObject::getControl(ConfigKey(group, "fwd"));
m_backButton = ControlObject::getControl(ConfigKey(group, "back"));

m_pKeyControl = new KeyControl(group, pConfig);
addControl(m_pKeyControl);

Expand Down Expand Up @@ -932,6 +929,7 @@ void EngineBuffer::processTrackLocked(
rate = m_rate_old;
}

double playpos_old = m_filepos_play;
bool at_end = m_filepos_play >= m_trackSamplesOld;
bool backwards = rate < 0;

Expand Down Expand Up @@ -973,6 +971,8 @@ void EngineBuffer::processTrackLocked(
// Note: The last buffer of a track is padded with silence.
// This silence is played together with the last samples in the last
// callback and the m_filepos_play is advanced behind the end of the track.
// If repeat is enabled, scaler->scaleBuffer() wraps around at end/start
// and fills the buffer with samples from the other end of the track.

if (m_bCrossfadeReady) {
// Bring pOutput with the new parameters in and fade out the old one,
Expand Down Expand Up @@ -1004,24 +1004,27 @@ void EngineBuffer::processTrackLocked(

m_scratching_old = is_scratching;

// Handle repeat mode
bool at_start = m_filepos_play <= 0;
at_end = m_filepos_play >= m_trackSamplesOld;

bool repeat_enabled = m_pRepeat->toBool();
// If we're repeating and crossed the track boundary, ReadAheadManager already
// wrapped around the playposition.
// To ensure quantize is respected we request a phase sync.
// TODO(ronso) This just restores previous repeat+quantize behaviour. I'm not
// sure whether that was actually desired or just a side effect of seeking.
// Ife it's really desired, should this be moved to looping control in order
// to set the sync'ed playposition right away and fill the wrap-around buffer
// with correct samples from the sync'ed loop in / track start position?
if (m_pRepeat->toBool() && m_pQuantize->toBool() &&
(m_filepos_play > playpos_old) == backwards) {
// TODO() The resulting seek is processed in the following callback
// That is to late
requestSyncPhase();
}

bool end_of_track = //(at_start && backwards) ||
(at_end && !backwards);
at_end = m_filepos_play >= m_trackSamplesOld;
bool end_of_track = at_end && !backwards;

// If playbutton is pressed, check if we are at start or end of track
if ((m_playButton->toBool() || (m_fwdButton->toBool() || m_backButton->toBool()))
&& end_of_track) {
if (repeat_enabled) {
double fractionalPos = at_start ? 1.0 : 0;
doSeekFractional(fractionalPos, SEEK_STANDARD);
} else {
m_playButton->set(0.);
}
// If playbutton is pressed and we're at the end of track release play button
if (m_playButton->toBool() && end_of_track) {
m_playButton->set(0.);
}

// Give the Reader hints as to which chunks of the current song we
Expand Down
2 changes: 0 additions & 2 deletions src/engine/enginebuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,6 @@ class EngineBuffer : public EngineObject {
ControlPushButton* m_stopStartButton;
ControlPushButton* m_stopButton;

ControlObject* m_fwdButton;
ControlObject* m_backButton;
ControlPushButton* m_pSlipButton;

ControlObject* m_pQuantize;
Expand Down
5 changes: 3 additions & 2 deletions src/engine/readaheadmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ SINT ReadAheadManager::getNextSamples(double dRate, CSAMPLE* pOutput,
//qDebug() << "start" << start_sample << requested_samples;

double target;
// A loop will only limit the amount we can read in one shot.
// A loop (beat loop or track on repeat) will only limit the amount we
// can read in one shot.
const double loop_trigger = m_pLoopingControl->nextTrigger(
in_reverse, m_currentPosition, &target);

Expand Down Expand Up @@ -115,7 +116,7 @@ SINT ReadAheadManager::getNextSamples(double dRate, CSAMPLE* pOutput,
if (reachedTrigger) {
DEBUG_ASSERT(target != kNoTrigger);

// Jump to other end of loop.
// Jump to other end of loop or track.
m_currentPosition = target;
if (preloop_samples > 0) {
// we are up to one frame ahead of the loop trigger
Expand Down
2 changes: 2 additions & 0 deletions src/test/readaheadmanager_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class ReadAheadManagerTest : public MixxxTest {
m_beatPrevCO(ConfigKey(kGroup, "beat_prev")),
m_playCO(ConfigKey(kGroup, "play")),
m_quantizeCO(ConfigKey(kGroup, "quantize")),
m_repeatCO(ConfigKey(kGroup, "repeat")),
m_slipEnabledCO(ConfigKey(kGroup, "slip_enabled")),
m_trackSamplesCO(ConfigKey(kGroup, "track_samples")),
m_pBuffer(SampleUtil::alloc(MAX_BUFFER_LEN)) {
Expand All @@ -105,6 +106,7 @@ class ReadAheadManagerTest : public MixxxTest {
ControlObject m_beatPrevCO;
ControlObject m_playCO;
ControlObject m_quantizeCO;
ControlObject m_repeatCO;
ControlObject m_slipEnabledCO;
ControlObject m_trackSamplesCO;
CSAMPLE* m_pBuffer;
Expand Down

0 comments on commit 7c55f3e

Please sign in to comment.