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

(fix) Waveform scratch crossing loop boundaries #13007

Merged
merged 2 commits into from
Apr 5, 2024
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
33 changes: 29 additions & 4 deletions src/engine/controls/ratecontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ RateControl::RateControl(const QString& group,
UserSettingsPointer pConfig)
: EngineControl(group, pConfig),
m_pBpmControl(nullptr),
m_wrapAroundCount(0),
m_jumpPos(mixxx::audio::FramePos()),
m_targetPos(mixxx::audio::FramePos()),
m_bTempStarted(false),
m_tempRateRatio(0.0),
m_dRateTempRampChange(0.0) {
Expand Down Expand Up @@ -441,10 +444,10 @@ double RateControl::calculateSpeed(double baserate, double speed, bool paused,
// The buffer is playing, so calculate the buffer rate.

// There are four rate effects we apply: wheel, scratch, jog and temp.
// Wheel: a linear additive effect (no spring-back)
// Wheel: a linear additive effect (no spring-back)
// Scratch: a rate multiplier
// Jog: a linear additive effect whose value is filtered (springs back)
// Temp: pitch bend
// Jog: a linear additive effect whose value is filtered (springs back)
// Temp: pitch bend

// New scratch behavior - overrides playback speed (and old behavior)
if (useScratch2Value) {
Expand All @@ -459,7 +462,17 @@ double RateControl::calculateSpeed(double baserate, double speed, bool paused,
}

double currentSample = frameInfo().currentPosition.toEngineSamplePos();
m_pScratchController->process(currentSample, rate, iSamplesPerBuffer, baserate);
// Let PositionScratchController also know if the play pos wrapped around
// (beatloop or track repeat) so it can correctly interpret the sample position delta.
m_pScratchController->process(currentSample,
rate,
iSamplesPerBuffer,
baserate,
m_wrapAroundCount,
m_jumpPos,
m_targetPos);
// Reset count after use.
m_wrapAroundCount = 0;

// If waveform scratch is enabled, override all other controls
if (m_pScratchController->isEnabled()) {
Expand Down Expand Up @@ -603,3 +616,15 @@ bool RateControl::isReverseButtonPressed() {
}
return false;
}

void RateControl::notifyWrapAround(mixxx::audio::FramePos triggerPos,
mixxx::audio::FramePos targetPos) {
VERIFY_OR_DEBUG_ASSERT(triggerPos.isValid() && targetPos.isValid()) {
m_wrapAroundCount = 0;
// no need to reset the position, they're not used if count is 0.
return;
}
m_wrapAroundCount++;
m_jumpPos = triggerPos;
m_targetPos = targetPos;
}
9 changes: 9 additions & 0 deletions src/engine/controls/ratecontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ class RateControl : public EngineControl {
static void setRateRampSensitivity(int);
static int getRateRampSensitivity();
bool isReverseButtonPressed();
// ReadAheadManager::getNextSamples() notifies us each time the play position
// wrapped around during one buffer process (beatloop or track repeat) so
// PositionScratchController can correctly interpret the sample position delta.
void notifyWrapAround(mixxx::audio::FramePos triggerPos,
mixxx::audio::FramePos targetPos);

public slots:
void slotRateRangeChanged(double);
Expand Down Expand Up @@ -147,6 +152,10 @@ public slots:
ControlProxy* m_pSyncMode;
ControlProxy* m_pSlipEnabled;

int m_wrapAroundCount;
mixxx::audio::FramePos m_jumpPos;
mixxx::audio::FramePos m_targetPos;

// This is true if we've already started to ramp the rate
bool m_bTempStarted;
// Set the Temporary Rate Change Mode
Expand Down
20 changes: 10 additions & 10 deletions src/engine/enginebuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -843,9 +843,9 @@ void EngineBuffer::processTrackLocked(
m_trackSampleRateOld = mixxx::audio::SampleRate::fromDouble(m_pTrackSampleRate->get());
m_trackEndPositionOld = getTrackEndPosition();

double baserate = 0.0;
double baseSampleRate = 0.0;
if (sampleRate.isValid()) {
baserate = m_trackSampleRateOld / sampleRate;
baseSampleRate = m_trackSampleRateOld / sampleRate;
}

// Sync requests can affect rate, so process those first.
Expand Down Expand Up @@ -875,7 +875,7 @@ void EngineBuffer::processTrackLocked(
// pass for every 1 real second). Depending on whether
// keylock is enabled, this is applied to either the rate or the tempo.
double speed = m_pRateControl->calculateSpeed(
baserate,
baseSampleRate,
tempoRatio,
paused,
iBufferSize,
Expand Down Expand Up @@ -980,10 +980,10 @@ void EngineBuffer::processTrackLocked(
// otherwise tempo and pitch are processed individual

double rate = 0;
// If the baserate, speed, or pitch has changed, we need to update the
// If the base samplerate, speed, or pitch has changed, we need to update the
// scaler. Also, if we have changed scalers then we need to update the
// scaler.
if (baserate != m_baserate_old || speed != m_speed_old ||
if (baseSampleRate != m_baserate_old || speed != m_speed_old ||
pitchRatio != m_pitch_old || tempoRatio != m_tempo_ratio_old ||
m_bScalerChanged) {
// The rate returned by the scale object can be different from the
Expand All @@ -1005,7 +1005,7 @@ void EngineBuffer::processTrackLocked(
m_pScale->clear();
}

m_baserate_old = baserate;
m_baserate_old = baseSampleRate;
m_speed_old = speed;
m_pitch_old = pitchRatio;
m_tempo_ratio_old = tempoRatio;
Expand All @@ -1016,16 +1016,16 @@ void EngineBuffer::processTrackLocked(
// main samplerate), the deck speed, the pitch shift, and whether
// the deck speed should affect the pitch.

m_pScale->setScaleParameters(baserate,
&speed,
&pitchRatio);
m_pScale->setScaleParameters(baseSampleRate,
&speed,
&pitchRatio);

// The way we treat rate inside of EngineBuffer is actually a
// description of "sample consumption rate" or percentage of samples
// consumed relative to playing back the track at its native sample
// rate and normal speed. pitch_adjust does not change the playback
// rate.
rate = baserate * speed;
rate = baseSampleRate * speed;

// Scaler is up to date now.
m_bScalerChanged = false;
Expand Down
Loading
Loading