Skip to content
Open
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
28 changes: 22 additions & 6 deletions core/src/orbit_delay_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -713,19 +713,35 @@ float OrbitDelayCore::processChannelFast(float input,
const float maxGuardBySize = 0.25f * delaySize;
const float guardSamples = clampf(kOrbitReadGuardMinSamples, 1.0f, maxGuardBySize);
if (readMode_ == ReadMode::AccidentalReverse) {
float reverseDelaySamples = params.tempoDelaySamples + spread + lfoSamples;
// Effective reverse delay follows the smoothed tempo delay plus the same
// channel-dependent offsets used by the forward path.
float reverseDelaySamples = params.tempoDelaySamples + params.offsetSamples + spread + lfoSamples;
reverseDelaySamples = clampf(reverseDelaySamples, guardSamples, fmaxf(delaySize - guardSamples, guardSamples));
float& reverseCounter = (&delay == &delayL_) ? reverseCounterL_ : reverseCounterR_;
float& reverseWindowSize = (&delay == &delayL_) ? reverseWindowSizeL_ : reverseWindowSizeR_;
const float readPos = wrapPosFloat(writePos - reverseDelaySamples + reverseCounter, delaySize, invDelaySize);
const float distanceBackward = wrapPosFloat(writePos - readPos, delaySize, invDelaySize);
if (distanceBackward < guardSamples || distanceBackward > (delaySize - guardSamples)) {

// Safe fallback: insufficient usable region between the two guard bands
// for the minimum reverse window size.
constexpr float kMinReverseWindowSamples = 8.0f;
if (delaySize < kMinReverseWindowSamples + 2.0f * guardSamples) {
reverseCounter = 0.0f;
reverseWindowSize = 0.0f;
reverseDelaySamples = guardSamples;
wet = 0.0f;
baseReadPos = wrapPosFloat(writePos - guardSamples, delaySize, invDelaySize);
Comment on lines 727 to +731

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The assignment reverseDelaySamples = guardSamples; is a dead store because reverseDelaySamples is a local variable that is not used anywhere else in this fallback branch. Removing it simplifies the code.

Suggested change
reverseCounter = 0.0f;
reverseWindowSize = 0.0f;
reverseDelaySamples = guardSamples;
wet = 0.0f;
baseReadPos = wrapPosFloat(writePos - guardSamples, delaySize, invDelaySize);
reverseCounter = 0.0f;
reverseWindowSize = 0.0f;
wet = 0.0f;
baseReadPos = wrapPosFloat(writePos - guardSamples, delaySize, invDelaySize);

} else {
const float readPos = wrapPosFloat(writePos - reverseDelaySamples + reverseCounter, delaySize, invDelaySize);
const float distanceBackward = wrapPosFloat(writePos - readPos, delaySize, invDelaySize);
if (distanceBackward < guardSamples || distanceBackward > (delaySize - guardSamples)) {
reverseCounter = 0.0f;
reverseWindowSize = 0.0f;
reverseDelaySamples = guardSamples;
}
// Window size is explicitly derived in readReverseWindowed() from this
// effective smoothed delay value.
wet = readReverseWindowed(delay, reverseDelaySamples, writePos, delaySize, invDelaySize, reverseCounter, reverseWindowSize);
baseReadPos = wrapPosFloat(writePos - reverseDelaySamples + reverseCounter, delaySize, invDelaySize);
Comment on lines +742 to +743

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

In the reverse-read path, baseReadPos is calculated using reverseCounter after it has been incremented inside readReverseWindowed(). This causes a 1-sample mismatch between the actual read position used for the wet signal and the base read position used for the feedback tap mixer. Calculating baseReadPos before calling readReverseWindowed() ensures they are perfectly aligned.

Suggested change
wet = readReverseWindowed(delay, reverseDelaySamples, writePos, delaySize, invDelaySize, reverseCounter, reverseWindowSize);
baseReadPos = wrapPosFloat(writePos - reverseDelaySamples + reverseCounter, delaySize, invDelaySize);
baseReadPos = wrapPosFloat(writePos - reverseDelaySamples + reverseCounter, delaySize, invDelaySize);
wet = readReverseWindowed(delay, reverseDelaySamples, writePos, delaySize, invDelaySize, reverseCounter, reverseWindowSize);

}
wet = readReverseWindowed(delay, reverseDelaySamples, writePos, delaySize, invDelaySize, reverseCounter, reverseWindowSize);
baseReadPos = wrapPosFloat(writePos - reverseDelaySamples + reverseCounter, delaySize, invDelaySize);
} else {
const float orbitDelaySamples = params.tempoDelaySamples * params.orbit;
const float modulatedDelaySamples = orbitDelaySamples + params.offsetSamples + spread + lfoSamples;
Expand Down