docs: close out Θ-W2-T1 filter-voice-path into COMPLETED
Move the landed filter-voice-path track from PLAN.md into COMPLETED.md with full narrative (quantizer removal, editor floor raise). Mark Θ-W2 fully landed, matching W1's phrasing; fix a stale forward reference.
This commit is contained in:
@@ -151,6 +151,44 @@ path.
|
||||
pre- vs post-envelope placement is sound-defining), the drive dial's calibration, and
|
||||
the fact that drive authority varies ~11 dB across the morph sweep.
|
||||
|
||||
### Θ-W2-T1 — filter-voice-path
|
||||
|
||||
Wires the pure filter module into ReaSampler 9000's per-voice signal path as a new fixed
|
||||
processing point between the pitch envelope and the amp stage, gives it its own
|
||||
knob-deck group, and relays the deck row in signal-flow order (pitch → filter → amp).
|
||||
Each `Voice` owns its own `VoiceFilter` and a second `AdsrEnvelope` instance — per-voice,
|
||||
never shared — and neither adds allocation or virtual dispatch to the per-sample path.
|
||||
Parameters — morph position, cutoff, Q, drive, mod amount (bipolar ±100%, targeting
|
||||
cutoff), velocity and key-tracking modulation, then AHDSR — live in the one parameter
|
||||
set; `FilterParams` stores the filter module's own `FilterSettings` by value rather than
|
||||
a parallel copy of the normalized positions. The filter is off by default and bit-exact
|
||||
off — a project saved before the change reopens sounding identical, pinned by a
|
||||
bit-equality test. `ComponentState`'s params payload moves v8 → v9, appending the filter
|
||||
tail; a v8 blob is a strict prefix and lifts to the off/neutral filter default, with
|
||||
non-finite filter fields falling back to neutral, pinned by a golden byte-literal
|
||||
fixture. Deck composition was extracted into a new pure module
|
||||
`core/instrument/ui/deck_groups`, with the pitch → filter → amp row order pinned by
|
||||
test; the filter's AHDSR ships as its own `FILTER ENV` group sibling to `FILTER`,
|
||||
mirroring the existing `PITCH` / `PITCH ENV` split, and a morph-law toggle (`Band` |
|
||||
`Notch`) ships as the FILTER group's row toggle.
|
||||
|
||||
**Deviations from spec:**
|
||||
- **An initial mod-quantizer was added, then rejected and removed.** A
|
||||
`kFilterModSteps = 2048` step gate on the coefficient re-solve stair-stepped the
|
||||
corner (~5.8 cents per step); Daniel rejected it. Replaced by a cutoff-only re-solve
|
||||
(`VoiceFilter::setCutoffNorm`) that re-derives only `g = tan(π·fc/sr)` — Q's parabola,
|
||||
the morph's cos/sin, and the folded mix are all cutoff-independent and stay cached
|
||||
from `prepare()`; `filter_params` hoists its constant logs. Measured at 48 kHz,
|
||||
Release, net of the sweep generator: kernel alone 2.8 ns/frame, full `prepare()` 56.9
|
||||
ns, cutoff-only re-solve 15.5 ns — about 1.2% of a core for 16 continuously-swept
|
||||
voices. The corner now sweeps continuously rather than stair-stepping.
|
||||
- **The editor floor was raised to 840×620**, which is also its new default size, up
|
||||
from a 560×460 floor at which the grown deck wrapped to four rows and pushed
|
||||
`FILTER ENV` / `AMP ENVELOPE` / `VOICE` / `MASTER` off-screen with no scroll.
|
||||
`kEditorMinWidth`/`kEditorMinHeight` now live in `sample_bands`, read by both the
|
||||
shell's `checkSizeConstraint` and the opening `ViewRect`. Consequence worth
|
||||
recording: a host with a saved editor rect below 840×620 is clamped up on reopen.
|
||||
|
||||
### Θ-W2-T2 — stereo-waveform-lanes
|
||||
|
||||
Delivered as specified: two stacked lanes, L above R, in stereo mode; one lane in mono;
|
||||
|
||||
Reference in New Issue
Block a user