-
-
Notifications
You must be signed in to change notification settings - Fork 50
Description
Bug
DelayNode.cpp has an inverted calculation in delayBufferOperation when handling ring-buffer wraparound. framesToEnd is computed as the overflow count (frames past the buffer end) rather than the pre-wrap count (frames remaining before the buffer end). This causes audio data to be written/read at incorrect positions in the ring buffer on every buffer boundary crossing.
File: packages/react-native-audio-api/common/cpp/audioapi/core/effects/DelayNode.cpp — line 49
// Current (buggy)
if (operationStartingIndex + framesToProcess > delayBuffer_->getSize()) {
int framesToEnd = operationStartingIndex + framesToProcess - delayBuffer_->getSize();framesToEnd is the overflow count. The code then processes framesToEnd frames at operationStartingIndex (near the buffer end), skipping the frames between operationStartingIndex + framesToEnd and bufferSize - 1.
Proposed fix:
int framesToEnd = static_cast<int>(delayBuffer_->getSize()) - static_cast<int>(operationStartingIndex);This gives the correct pre-wrap count: frames remaining before the buffer end. The subsequent second chunk then handles the overflow frames correctly at position 0.
Symptoms on Android (Nokia XR20, Android 14, sampleRate 48000)
- Periodic metronome-like clicking whose rate scales with
delayTime.valuehigher values produce faster ticking. This is consistent with buffer boundary artifacts repeating at intervals tied to the delay time. - The delay echo effect is barely audible or not audible despite correct parameter values.
- When
DelayNodeis wired into the audio graph (even with wet gain = 0), the dry audio path is disrupted, and audio only plays when the delay is actively producing output.
Applying the one-line fix above did not fully eliminate the artifacts on our device, suggesting there may be at least one additional bug elsewhere in the implementation (possibly in AudioBus::sum or the overall processNode scheduling), but the ring buffer calculation is clearly wrong and worth fixing independently.
Reproduction
const ctx = new AudioContext();
const osc = ctx.createOscillator();
const delay = ctx.createDelay(1.0);
delay.delayTime.value = 0.3;
const wet = ctx.createGain();
wet.gain.value = 0.5;
osc.connect(ctx.destination); // dry
osc.connect(delay);
delay.connect(wet);
wet.connect(ctx.destination); // wet
osc.start();
ctx.resume();
// Expected: clean sine + echo at 300ms
// Actual: periodic clicking, echo inaudible or corruptedVersions affected
- 0.11.6 ✗
- 0.11.7 ✗ (same code)
Platform: Android only (not tested on iOS)