You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: seven defects a max-effort review found in the preset work
All seven are in code from this stack, and five are in the preset wet/dry
wrap and its removal path — the newest work, and the least exercised.
**Two produce a wrong render.**
`shapeOf` carried no preset identity, so a reorder that preserved the
effect-type sequence took the in-place update path and left the wet/dry
wrap bracketing the wrong node. Add "Tame Boominess" (a peaking node),
add the "Add Clarity" job (also peaking), move one past the other: the
shape string is unchanged, so preview keeps its old wiring and blends out
the author's own effect while the render, which rebuilds, blends out the
preset's. Same class as the one-pole cutoff and the phaser waveform
already encoded there — state that is WIRED at construction has to be in
the signature.
`FxChainHandle.presets` was a Record keyed by preset id, but `presetRuns`
legitimately emits several runs for one preset once a reorder splits it.
The second wrap overwrote the first, and `update` looked wraps up with
`find`, so a split preset wrote one wrap twice and never touched the
other: the switch read "Off" while the audio was unchanged, and an
`fx.preset.<id>` lane drove one fragment. Targets accumulate per id now,
and the update walks wraps in build order.
**Two lose or resurrect automation lanes.**
`removeRun` called `onRemoveNodeAutomation` per node in a loop. Each call
recomputes from the same render-time snapshot and replaces the whole
attribute, so every write but the last was discarded and the earlier
nodes' lanes survived as orphans — which the next effect added inherits,
because ids are minted lowest-free, arriving "Automated" with an envelope
nobody drew. One batched call now takes every id at once. `removeEq` had
the identical loop; it was only unreachable because EQ bands expose no
automation toggle.
It also never removed the whole-preset `fx.preset.<id>` lane, which
belongs to no node, so re-applying the preset later resurrected an old
ramp. The batched call takes the preset id too.
**Three more.**
The levelling script measured the whole decoded file from sample 0 while
lane times are clip-local, so any clip with `data-media-start` got an
envelope offset by exactly the trim — corrections landing on the wrong
passages, worse than not levelling. It now measures the clip's own window.
`audioFxProfileStrength` inverted every profile with a straight line, but
the reverb's `size` curve is piecewise because the design's anchors are
not evenly spaced. Setting Space to 0.5 read back as 0.46, and each
reopen moved the sound again. It searches the curve at the knob's own
0.01 resolution instead — searching only reachable values is what makes
the round trip exact rather than one step off.
The `audio_volume_double_automation` probe was narrowed to `[^;)]` in
this stack to stop it blaming the wrong element in a chained timeline.
That silenced it for any object holding a call —
`{ duration: fadeTime(2), volume: 0.2 }` — which is ordinary rather than
exotic. A depth-counted scan crosses nested parens and still stops at the
end of the selector's own call, which neither fixed bound could do.
Each fix has a test that fails without it; every one was falsified by
reverting the fix and watching it fail.
Not fixed, and reported as a false positive: the claim that a node id of
`"preset"` would have its lanes reinterpreted. `mintAudioFxNodeId` only
ever produces `n1`, `n2`, …, which is why that slot was reserved.
core 1774 · studio 3732 + 18 todo · engine services 739 + 3 · lint 520.
0 commit comments