The floor mix routes source → dryGain → dest in parallel with source → worklet → … → wetGain → dest. The comment justifies this for "low-latency" models, but RNNoise is a framed algorithm (480-sample / 10 ms frames at 48 kHz) and the sapphi worklet adds its own ring-buffer delay, so the two paths are offset by at least one frame. Summing them produces comb filtering with notches spaced by the inverse of that delay — a hollow/phasey colouration on voice, which is the same family of artefact ("robotic/underwater") the floor was added to fix. At floor = 0.15 the notches are shallow (~-1.4 dB), so it is a quality regression rather than a breakage, but it partially cancels the intended benefit.
How to trigger
A/B lotusDenoiseFloor=0 vs the default 0.15 on RNNoise with a steady tone; the floored version shows periodic nulls in the spectrum.
Suggested fix
Insert a DelayNode on the dry path matched to the model's algorithmic latency (measurable once, per model), or replace the parallel dry mix with a post-worklet noise-floor generator.
Filed from the September 2026 audit (branch lotus).
**Severity:** low · **Type:** bug · **Confidence:** medium
**Location:** `src/lotus/lotusDenoiseProcessor.ts:285-314`
### Problem
The floor mix routes `source → dryGain → dest` in parallel with `source → worklet → … → wetGain → dest`. The comment justifies this for "low-latency" models, but RNNoise is a framed algorithm (480-sample / 10 ms frames at 48 kHz) and the sapphi worklet adds its own ring-buffer delay, so the two paths are offset by at least one frame. Summing them produces comb filtering with notches spaced by the inverse of that delay — a hollow/phasey colouration on voice, which is the same family of artefact ("robotic/underwater") the floor was added to fix. At `floor = 0.15` the notches are shallow (~-1.4 dB), so it is a quality regression rather than a breakage, but it partially cancels the intended benefit.
### How to trigger
A/B `lotusDenoiseFloor=0` vs the default `0.15` on RNNoise with a steady tone; the floored version shows periodic nulls in the spectrum.
### Suggested fix
Insert a `DelayNode` on the dry path matched to the model's algorithmic latency (measurable once, per model), or replace the parallel dry mix with a post-worklet noise-floor generator.
---
_Filed from the September 2026 audit (branch `lotus`)._
jared
added this to the EC fork audit 2026-09 · Medium & Low milestone 2026-09-12 02:13:10 -04:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Severity: low · Type: bug · Confidence: medium
Location:
src/lotus/lotusDenoiseProcessor.ts:285-314Problem
The floor mix routes
source → dryGain → destin parallel withsource → worklet → … → wetGain → dest. The comment justifies this for "low-latency" models, but RNNoise is a framed algorithm (480-sample / 10 ms frames at 48 kHz) and the sapphi worklet adds its own ring-buffer delay, so the two paths are offset by at least one frame. Summing them produces comb filtering with notches spaced by the inverse of that delay — a hollow/phasey colouration on voice, which is the same family of artefact ("robotic/underwater") the floor was added to fix. Atfloor = 0.15the notches are shallow (~-1.4 dB), so it is a quality regression rather than a breakage, but it partially cancels the intended benefit.How to trigger
A/B
lotusDenoiseFloor=0vs the default0.15on RNNoise with a steady tone; the floored version shows periodic nulls in the spectrum.Suggested fix
Insert a
DelayNodeon the dry path matched to the model's algorithmic latency (measurable once, per model), or replace the parallel dry mix with a post-worklet noise-floor generator.Filed from the September 2026 audit (branch
lotus).