Skip to content

Commit

Permalink
PositionScratchController: fix false high rate seeking
Browse files Browse the repository at this point in the history
  • Loading branch information
ronso0 committed Feb 10, 2025
1 parent 1d440fc commit 91beaea
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 9 deletions.
4 changes: 4 additions & 0 deletions src/engine/controls/ratecontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -613,3 +613,7 @@ void RateControl::notifyWrapAround(mixxx::audio::FramePos triggerPos,
m_jumpPos = triggerPos;
m_targetPos = targetPos;
}

void RateControl::notifySeek(mixxx::audio::FramePos position) {
m_pScratchController->notifySeek(position);
}
1 change: 1 addition & 0 deletions src/engine/controls/ratecontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class RateControl : public EngineControl {
// PositionScratchController can correctly interpret the sample position delta.
void notifyWrapAround(mixxx::audio::FramePos triggerPos,
mixxx::audio::FramePos targetPos);
void notifySeek(mixxx::audio::FramePos position) override;

public slots:
void slotRateRangeChanged(double);
Expand Down
51 changes: 42 additions & 9 deletions src/engine/positionscratchcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ PositionScratchController::PositionScratchController(const QString& group)
m_isScratching(false),
m_inertiaEnabled(false),
m_prevSamplePos(0),
// TODO we might as well use FramePos in order to use more convenient
// mixxx::audio::kInvalidFramePos, then convert to sample pos on the fly
m_seekSamplePos(std::numeric_limits<double>::quiet_NaN()),
m_samplePosDeltaSum(0),
m_scratchTargetDelta(0),
m_scratchStartPos(0),
Expand Down Expand Up @@ -159,6 +162,15 @@ void PositionScratchController::process(double currentSamplePos,
slotUpdateFilterParameters(m_pMainSampleRate->get());
}

bool adoptSeekPos = false;
if (!util_isnan(m_seekSamplePos)) {
// If we were notified about a seek, adopt the new position immediately.
m_prevSamplePos = m_seekSamplePos;
m_seekSamplePos = std::numeric_limits<double>::quiet_NaN();

adoptSeekPos = true;
}

double scratchPosition = 0;
m_mouseSampleTime += m_dt;
if (m_mouseSampleTime >= kDefaultSampleInterval || !m_isScratching) {
Expand Down Expand Up @@ -277,13 +289,26 @@ void PositionScratchController::process(double currentSamplePos,
}

if (calcRate) {
double ctrlError = m_pRateIIFilter->filter(
scratchTargetDelta - m_samplePosDeltaSum);
m_rate = m_pVelocityController->observation(ctrlError);
m_rate /= ceil(kDefaultSampleInterval / m_dt);
if (fabs(m_rate) < MIN_SEEK_SPEED) {
// we cannot get closer
if (adoptSeekPos) {
// If we just adopted the seek we need to avoid false high rate
// and simply assume rate 0.
// See comment in notifySeek().
m_rate = 0;
} else {
double ctrlError = m_pRateIIFilter->filter(
scratchTargetDelta - m_samplePosDeltaSum);
m_rate = m_pVelocityController->observation(ctrlError);
m_rate /= ceil(kDefaultSampleInterval / m_dt);
// ??
// Note: The following SoundTouch changes the also rate by a ramp
// This looks like average of the new and the old rate independent
// from m_dt. Ramping is disabled when direction changes or rate = 0;
// (determined experimentally)
if (fabs(m_rate) < MIN_SEEK_SPEED) {
// we cannot get closer
// TODO ramp to new rate?
m_rate = 0;
}
}
}

Expand Down Expand Up @@ -321,7 +346,15 @@ void PositionScratchController::process(double currentSamplePos,

void PositionScratchController::notifySeek(mixxx::audio::FramePos position) {
DEBUG_ASSERT(position.isValid());
// scratching continues after seek due to calculating the relative distance traveled
// in m_samplePosDeltaSum
m_prevSamplePos = position.toEngineSamplePos();
const double newPos = position.toEngineSamplePos();
if (!isEnabled()) {
// not scratching, ignore";
return;
} else if (m_prevSamplePos == newPos) {
// no-op
return;
}
// Scratching continues after seek due to calculating the relative
// distance traveled in m_samplePosDeltaSum
m_seekSamplePos = newPos;
}
1 change: 1 addition & 0 deletions src/engine/positionscratchcontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class PositionScratchController : public QObject {
bool m_isScratching;
bool m_inertiaEnabled;
double m_prevSamplePos;
double m_seekSamplePos;
double m_samplePosDeltaSum;
double m_scratchTargetDelta;
double m_scratchStartPos;
Expand Down

0 comments on commit 91beaea

Please sign in to comment.