Widen the deck row block to 1028 so the filter tie-line is exact, and accumulate the meter's block peaks instead of sampling one in 47

This commit is contained in:
2026-08-02 08:27:05 -04:00
parent 0627398bbb
commit df10ddacc2
29 changed files with 552 additions and 250 deletions
+4 -1
View File
@@ -970,7 +970,10 @@ from `knob_deck.h` into `sample_bands.h` alongside the min-width/min-height pair
is a window fact rather than a deck one; the deck's own width-budget constants — the row
block (1020) and MASTER's reserved width (142) — stay in `knob_deck.h`. The floor is
derived rather than asserted as a literal: `1020 + 12 (gap) + 142 + 2×8 (pad) = 1190`,
leaving 90 px of headroom against the 1280 px ceiling. Row membership becomes a property of
leaving 90 px of headroom against the 1280 px ceiling. (**Both numbers moved afterwards:**
Γ-W3-T1 widened the block to 1028 and the floor to 1198 — 82 px of headroom — so the
justification law makes the filter tie-line exact. This paragraph is what W1-T4 landed.)
Row membership becomes a property of
the group id — `DeckRow { Sound, Contour, Spanning }` plus `deckRowFor(DeckGroupId)`, an
exhaustive switch (Sound = PITCH/RATE, FILTER, VELOCITY, VOICE; Contour = PITCH ENV, FILTER
ENV, AMP ENVELOPE; Spanning = MASTER) so a future group left unclassified is a compile
+26 -17
View File
@@ -625,7 +625,7 @@ folded into the tracks below:
table freezes. The editor's visual rows after the reflow were the rejected alternative.
**The reason, because a future reader will ask why the id order does not match the screen:**
the editor's layout has already moved twice (Θ-W6-T1 grew the floor 840 → 980; Γ-W3-T1 takes
it to 1190 and re-rows every group) and within-row order is settled by width fitting, not by
it to 1198 and re-rows every group) and within-row order is settled by width fitting, not by
meaning — so **binding a permanently-frozen id order to a demonstrably mobile layout
guarantees the two drift apart**, after which the order is neither logical nor matching.
Signal flow is the axis that does not move. Full argument and the accepted residual cost:
@@ -693,7 +693,7 @@ see "The wave shape after Ruling 1" below.
1. **The reflow is split, canvas from arrangement.** The window floor and the width budget it
is derived from land **early** (Γ-W1-T4), so every other UI track in the phase is drawn,
tested and judged at the final 1190 × 680 window instead of at a size a later wave changes
tested and judged at the final 1198 × 680 window instead of at a size a later wave changes
under it. The two-row *arrangement* stays late (Γ-W3-T1), because it can only be measured
once the final PITCH/RATE and MASTER descriptors exist. The seam is stated at Γ-W1-T4.
2. **`preserve-time-stretch` moved W4 → W1-T5.** It is the longest pole in the phase and has
@@ -825,10 +825,13 @@ exact interim layout; do not "fix" it in a track that does not own it.
- **The exposed parameter set is DERIVED, never hand-maintained.** A control is a parameter
if and only if its commit class is `Live` or `NoteOnLatched`. There is no second table
beside `deckParamCommit` / `liveCommitFor`, and no list that can drift from it.
- **The window floor is 1190 × 680 and must not exceed 1280 × 720.** **Γ-W1-T4 sets it, in
wave 1; no other track in the phase may move it**, and from that point every track is
- **The window floor is 1198 × 680 and must not exceed 1280 × 720.** **Γ-W1-T4 set it at
1190, in wave 1; no other track in the phase may move it** — with ONE ruled exception,
Daniel 2026-08-02: Γ-W3-T1 widened the row block 1020 → 1028 and the floor 1190 → 1198, so
the justification law puts both rows' filter edges on one pixel (spec §1.3). That is the
only reopening, and only these two constants moved. From that point every track is
authored and judged at it. A track that pushes the floor past 1280 has failed, not overrun.
**`kEditorMinHeight` stays 680** (Γ-F1). The remaining **90 px of width headroom is the
**`kEditorMinHeight` stays 680** (Γ-F1). The remaining **82 px of width headroom is the
budget for the life of this layout** — one deck cell is 60 px, so there is room for exactly
one more, once. Spec §1.6 states the ledger; read it before adding any control. Chrome-row
additions are a **separate purse** (they are paid for out of the title slot, not the floor)
@@ -900,7 +903,9 @@ into `sample_bands.h`) — leaving 90 px of headroom. Row membership becomes a p
group id via an exhaustive `deckRowFor(DeckGroupId)` switch (Sound / Contour / Spanning),
consumed by no one yet — **that consumption, and the fit inside the 1020 block, is
Γ-W3-T1's** to assert. No drawing code, descriptor, parameter, or audio changed in this
track.
track. **Superseded in part:** Γ-W3-T1 asserted the fit and found 1020 could not deliver the
tie-line it was chosen for, so the block is now 1028 and the floor 1198 — see that track's
block below.
#### Γ-W1-T5 — `preserve-time-stretch`
@@ -1063,14 +1068,18 @@ waveform band.
divided equally among the row's (n1) gutters, integer residue to the leftmost;
**no gutter narrower than `kDeckGroupGap` (12)**. **Decks are never stretched.** MASTER is
not part of either row's justification.
- **Row block = 1020 px at the floor**, giving row 1 gutters 12/14/14 and row 2 gutters 72/72,
at which width **FILTER's right edge and FILTER ENV's right edge both land on x = 636**.
That tie-line, row 2's equal gutters, and row 1's minimum gutter being exactly
`kDeckGroupGap` all hold at 1020 and only at 1020 — **this is why the floor is 1190 and not
1186.** Above the floor the tie-line drifts and that is accepted (spec §1.3).
- **The floor is already 1190 × 680 and the bands are already 216 / 358** — Γ-W1-T4 landed all
- **Row block = 1028 px at the floor** (widened from the originally specified 1020 — Daniel,
2026-08-02), giving row 1 gutters 16/16/16 and row 2 gutters 76/76, at which width
**FILTER's right edge and FILTER ENV's right edge both land on x = 640**. The tie-line and
both rows' equal gutters hold at 1028 because each row's slack divides by its gutter count
with no residue. **This is why the floor is 1198 and not 1190.** The originally specified
1020 delivered NEITHER the tie-line (638 vs 636) nor the claimed exactly-`kDeckGroupGap`
smallest gutter (13); the three properties were never simultaneously satisfiable, and 12 is
a floor rather than a target — spec §1.3 records all three deviations. Above the floor the
tie-line drifts and that is accepted (spec §1.3).
- **The bands are already 216 / 358 and the floor was already 1190 × 680** — Γ-W1-T4 landed all
four in wave 1, and the greedy wrap happened to reach two rows at that width. **This track
changes none of those numbers; it makes them true by construction instead of by coincidence.**
changes only the row block and the floor (see above); the rest it makes true by construction rather than by coincidence.**
Row 1's natural width fits the block **only after this track's `Band|Notch` move**: 1030
today, +42 from W2-T1's PITCH/RATE, 92 here, = **980**. That is this track's fit assertion
and W1-T4 deliberately left it open.
@@ -1109,10 +1118,10 @@ waveform band.
natural width is mode-stable at 876 because the reserve slots hold FILTER ENV and AMP at
312 in both modes — assert it).
- Row 1 and row 2 are **flush left and flush right**; at the floor width the filter tie-line
is exact (both edges at x = 636) and row 2's two gutters are equal.
- **Row 1's natural width is 980 and fits the 1020 block** — the fit Γ-W1-T4 could not yet
is exact (both edges at x = 640) and BOTH rows' gutters are equal.
- **Row 1's natural width is 980 and fits the 1028 block** — the fit Γ-W1-T4 could not yet
assert, closed here by the `Band|Notch` move.
- **`kEditorMinWidth` is still 1190 and the floor is still ≤ 1280 × 720** — unchanged by this
- **`kEditorMinWidth` is 1198 and the floor is still ≤ 1280 × 720** — moved 1190 → 1198 by this
track, verified against Γ-W1-T4's derived test rather than a second copy of it.
- The waveform band is **358 px at the floor**, and the deck band is 216 — **unchanged from the
interim, now reached by construction**: `deckRowCount` at and above the floor is 2 because the
@@ -3633,7 +3642,7 @@ Phase Γ — The instrument's control surface (none of the seventeen; ends
+ 10 s ceiling + AHDSR schematic axis [Ruling 2]
T2 master-bus-audio ........... limiter + meter ballistics + dynamic PDC [rung 1]
T3 contour-trace-curves ....... staged traces draw curved, knot on its trace
T4 editor-floor-and-row-law ... floor 1190x680 + budget constants + row predicate
T4 editor-floor-and-row-law ... floor 1190x680 (W3-T1: 1198) + budget constants + row predicate
T5 preserve-time-stretch ...... real stretcher [measure-and-report gate]
T6 exhaustive-switch gate on pure libraries ... /we4062, -Werror=switch on
pure libraries [no PLAN entry — see COMPLETED.md]
+62 -38
View File
@@ -31,14 +31,15 @@ own width formula, not carried over from a prior measurement. The stale geometry
**PITCH/RATE | FILTER | VELOCITY | VOICE** (sound). Row 2 is **PITCH ENV | FILTER ENV |
AMP ENVELOPE** (contour). **MASTER spans both rows on the far right.**
- **The arithmetic closes, with room.** Minimum/default window goes **980 × 680 →
1190 × 680**, inside the settled 1280 × 720 ceiling with **90 px of headroom**. The deck
1198 × 680**, inside the settled 1280 × 720 ceiling with **82 px of headroom**. The deck
band drops **328 → 216 px**, returning **112 px to the waveform** (246 → 358 px at the
floor). **That 90 px is the governing budget for every future control addition** — one
floor). **That 82 px is the governing budget for every future control addition** — one
deck cell is 60 px, so the layout has room for exactly one more, once. §1.6.
- **The two rows align exactly, not nearly.** At the floor width the row block is 1020 px,
and at that width row 2's two gutters are equal (72 px each) *and* FILTER's right edge
lands exactly on FILTER ENV's right edge (both at x = 636). That is the aesthetic tie
between the rows and it falls out of the arithmetic — §1.3.
- **The two rows align exactly, not nearly.** At the floor width the row block is 1028 px,
and at that width BOTH rows' gutters are equal (16/16/16 and 76/76) *and* FILTER's right
edge lands exactly on FILTER ENV's right edge (both at x = 640). That is the aesthetic tie
between the rows and it falls out of the arithmetic — §1.3, which also records the three
properties the originally-specified 1020 block was claimed to deliver and did not.
- **PITCH becomes PITCH/RATE**: three knobs (`Key Trk | Rate | Pitch`) under the existing
Varisp|Presrv toggle. Rate 50200 % exponential, Pitch ±24 st.
- **MASTER becomes the post-voice-mixer deck it was always reserved to be**: limiter
@@ -117,30 +118,31 @@ and `knobRowWidth = |cellIds|·kDeckCellW (+ 4 + 2·segWidth for a rowToggle)`.
| | Natural content | Gutters at floor | **Row width** |
|---|---|---|---|
| Row 1 | 192 + 432 + 192 + 164 = **980** | 12 + 14 + 14 = 40 | **1020** |
| Row 2 | 252 + 312 + 312 = **876** | 72 + 72 = 144 | **1020** |
| Row 1 | 192 + 432 + 192 + 164 = **980** | 16 + 16 + 16 = 48 | **1028** |
| Row 2 | 252 + 312 + 312 = **876** | 76 + 76 = 152 | **1028** |
**Window floor.**
```
deck band width = 1020 (row block) + 12 (kDeckGroupGap) + 142 (MASTER) = 1174
kEditorMinWidth = 1174 + 2·kPad(8) = 1190
deck band width = 1028 (row block) + 12 (kDeckGroupGap) + 142 (MASTER) = 1182
kEditorMinWidth = 1182 + 2·kPad(8) = 1198
kEditorMinHeight = 680 (unchanged)
deck band height = 2·kDeckGroupH(104) + kDeckRowGap(8) = 216 (was 328)
waveform band at the floor = 680 90 (chrome) 4 4 8 216 = 358 (was 246)
```
**1190 × 680, against a 1280 × 720 ceiling — 90 px of width headroom, 40 px of height.**
**1198 × 680, against a 1280 × 720 ceiling — 82 px of width headroom, 40 px of height.**
> **Who lands which half.** The floor, the three budget constants it is derived from
> (row block 1020 · MASTER 142 · ceiling 1280) and each group's row membership land in
> (row block · MASTER 142 · ceiling 1280) and each group's row membership land in
> **Γ-W1-T4**, in wave 1, so the rest of the phase is authored at the final window. The
> arrangement *inside* that budget — the justification law, the gutters, the tie-line,
> MASTER's interior — is **Γ-W3-T1**, because every one of those measures a descriptor that
> does not exist until Γ-W2-T1 and Γ-W3-T1 create it. **Row 1's natural width does not fit
> the 1020 block until Γ-W3-T1**: it is 1030 today, +42 from PITCH/RATE, 92 from FILTER's
> `Band|Notch` caption move, = 980. Row 2's 876 already fits. `docs/PLAN.md` at Γ-W1-T4
> states the seam and the interim layout in full.
> the block until Γ-W3-T1**: it is 1030 today, +42 from PITCH/RATE, 92 from FILTER's
> `Band|Notch` caption move, = 980. Row 2's 876 already fits. Γ-W1-T4 set the block at 1020
> and the floor at 1190; the widen recorded below moved both, and it is the ONLY number of
> W1-T4's that this phase reopened. `docs/PLAN.md` at Γ-W1-T4 states the seam in full.
Three corrections to the arithmetic in the brief, all small and all in our favour:
@@ -148,9 +150,13 @@ Three corrections to the arithmetic in the brief, all small and all in our favou
ceiling with zero slack. 142 is what the deck's own content actually needs (§1.4) and
it banks 94 px. MASTER may grow to **236** before the ceiling binds; that is the
meter's growth room, not a target.
2. **The row block is 1020, not 1016.** The extra 4 px is deliberate and is what makes the
two rows align exactly rather than 2 px apart — §1.3. It is the single cheapest
aesthetic purchase in the phase.
2. **The row block is 1028, not 1016 and not the 1020 originally specified.** 1020 was
chosen to make the two rows align exactly; it does not — 1020 leaves row 1 a 40 px slack
that three gutters cannot divide evenly, so the justification law produces 14/13/13 and
leaves FILTER's right edge 2 px past FILTER ENV's. **1028 is the width at which the law
itself makes the tie-line exact**, with no residue in either row (§1.3). The 8 px is the
single cheapest aesthetic purchase in the phase, and it is spent from the headroom
ledger in §1.6.
3. **VOICE keeps its row toggle** — confirmed. Moving `Retrig|Legato` to the caption gives
`38 + 4 + 80 + 4 + 88 = 214`**226 px**, wider than 164, because VOICE's caption row is
the binding side and its knob row is nearly empty. Leave it.
@@ -182,11 +188,24 @@ approximate:
share a right edge.
2. **The filter tie-line.** At the floor width the two rows' filter groups end on the same
pixel:
`row 1: 192 + 12 + 432 = 636` · `row 2: 252 + 72 + 312 = 636`.
That is not a coincidence to be preserved by a special rule — it is what row-block
width **1020** buys, and at 1020 row 2's two gutters are *also* exactly equal (72/72)
and row 1's smallest gutter is *exactly* `kDeckGroupGap`. Three good properties at one
width. **This is why the floor is 1190 and not 1186.**
`row 1: 192 + 16 + 432 = 640` · `row 2: 252 + 76 + 312 = 640`.
That is not a coincidence preserved by a special rule — it is what row-block width
**1028** buys, and at 1028 both rows' gutters are *also* exactly equal (16/16/16 and
76/76), because 1028 leaves each row a slack its gutter count divides with no residue.
**This is why the floor is 1198 and not 1190.**
> **Corrected 2026-08-02 — this paragraph previously claimed THREE properties at 1020,
> and none of the three held there.** It said the tie-line landed at 636, that row 2's
> gutters were equal, and that row 1's *smallest gutter was exactly* `kDeckGroupGap` (12).
> What 1020 actually produced: row 1's slack is 40 over three gutters, so the law's
> equal-division-plus-leftmost-residue rule gives **14/13/13** — not 12/14/14 as §1.2's
> table stated, and not a smallest gutter of 12 — and FILTER's right edge lands on **638**
> against row 2's 636. Only row 2's equal gutters held. The three were never
> simultaneously satisfiable: the tie-line needs 1028, an exactly-12 smallest gutter needs
> 1016, and 1020 delivered neither. **`kDeckGroupGap` is a FLOOR — "no gutter narrower
> than 12" — never a target**, so the 16 px gutters at 1028 satisfy the real rule and the
> third property is withdrawn rather than traded away. Two properties hold at 1028, both
> exactly, and the law is what makes them hold.
3. **Shared horizontal baselines.** Every group is `kDeckGroupH` with identical interior
offsets, so across both rows the caption text, the knob centrelines and the label bands
sit on the same four lines. The reflow must not break this — it is free today and
@@ -249,32 +268,37 @@ Horizontally the group is `6 + 60 + 8 + 62 + 6 = 142`.
| Deck rows at the floor width | 3 (by greedy wrap) | **2 (by construction)** |
| Deck band height | 328 | **216** |
| Waveform band at the floor | 246 | **358** |
| Minimum / default window | 980 × 680 | **1190 × 680** |
| Ceiling headroom | — | **90 px wide, 40 px tall** |
| Minimum / default window | 980 × 680 | **1198 × 680** |
| Ceiling headroom | — | **82 px wide, 40 px tall** |
**Costs, named.** The floor width grows by 210 px — an existing saved instance's window
**Costs, named.** The floor width grows by 218 px — an existing saved instance's window
grows on open (the same one-time effect Θ-W6-T1 already shipped at 840 → 980, so the
behaviour is precedented, not new). The deck's wrap mechanism stops being the thing that
decides row membership at the floor width (§7.3). And the phase spends its ceiling headroom
budget — §1.6.
### 1.6 The 90 px headroom is the budget, and it governs every future control
### 1.6 The 82 px headroom is the budget, and it governs every future control
**Read this before proposing any new knob.** The floor is **1190** against Daniel's hard
**1280** ceiling. That is **90 px of width headroom for the life of this layout**, and it is
**Read this before proposing any new knob.** The floor is **1198** against Daniel's hard
**1280** ceiling. That is **82 px of width headroom for the life of this layout**, and it is
the single constraint every later addition spends from:
| Purchase | Cost | Headroom after |
|---|---|---|
| One more 60 px deck cell on row 1 | 60 | 30 |
| One more caption toggle on a group whose caption row is the binding side | 048 | 4290 |
| Widening MASTER to a two-cell left column | 60 | 30 |
| One more 60 px deck cell on row 1 | 60 | 22 |
| One more caption toggle on a group whose caption row is the binding side | 048 | 3482 |
| Widening MASTER to a two-cell left column | 60 | 22 |
| A second cell *and* a wider MASTER | 120 | **over ceiling** |
**The ledger was 90 until the row block widened 1020 → 1028** (§1.2 correction 2, §1.3). Its
*purchasing power* is unchanged: one more 60 px deck cell remains affordable (82 60 = 22),
which is the only purchase this ledger has ever promised, and the second one was already over
the ceiling at 90. The 8 px came out of the spare change, not out of the budget's one slot.
**This is why MASTER's reserved lower-left slot is ONE cell and not two** (Γ-F5, ruled by
Daniel 2026-08-01). A two-cell reserve would spend 60 of the 90 up front, on a control
Daniel 2026-08-01). A two-cell reserve would spend 60 of the 82 up front, on a control
nobody has named yet, and would effectively freeze row 1 forever: any later row-1 addition
would then need the remaining 30 px and would not have it. One cell keeps the spare. If the
would then need the remaining 22 px and would not have it. One cell keeps the spare. If the
future master-bus control turns out to be two knobs, widening MASTER **then** costs the same
60 px it would cost now, and by then the trade is being made against a real control instead
of a guess. **Reserving capacity you have not designed a use for is not free here — it is
@@ -1167,8 +1191,8 @@ Three reasons for that exact slot:
2. **Browse stays rightmost.** It is navigation, not a mode — moving it would break the
established right-edge reading.
3. **It costs zero window width.** The run is right-anchored and the title slot absorbs it,
so `kEditorMinWidth` does not move and **none of §1.6's 90 px headroom is spent.**
*Constraint:* the title slot must still hold its text at the 1190 floor. If it will not,
so `kEditorMinWidth` does not move and **none of §1.6's 82 px headroom is spent.**
*Constraint:* the title slot must still hold its text at the 1198 floor. If it will not,
the enable's segments narrow — the floor does not move. That is a hard rule, because the
floor is a phase-wide acceptance criterion.
@@ -1402,7 +1426,7 @@ ceiling.
| **Γ-F2** | Limiter lookahead, or zero-latency? | **Lookahead with DYNAMIC reported latency** — zero when off, the lookahead when on, reported to the host's PDC. *Overrides this doc's zero-lookahead recommendation.* | **§3.1.1** (new), §7.10 |
| **Γ-F3** | Does the log taper raise the 2 s stage-time ceiling? | **REVERSED, same day. Ruled first "not in this phase — stays 2.0 s"; then Daniel: _"extend the stage lengths to 10s."_ The ceiling moves 2.0 → 10.0 in Γ-W1-T1.** The reversal's cause is Ruling 1: parameters now ship in-phase, so the ceiling is a one-way door that has to be walked through *before* them. | **§4.3.1** (new), §4.3; `docs/TODO.md` entry discharged |
| **Γ-F4** | Explicit loop enable? | **Yes — on the CHROME ROW.** Not a deck cell; loop is a waveform-overlay concept and has no deck. | **§6.4** (new), §6.5, §7.9 |
| **Γ-F5** | MASTER's reserved slot: one cell or two? | **One cell.** Two would spend 60 of the 90 px headroom on an unnamed control and freeze row 1 forever. | **§1.6** (new), §1.4 |
| **Γ-F5** | MASTER's reserved slot: one cell or two? | **One cell.** Two would spend 60 of the 82 px headroom on an unnamed control and freeze row 1 forever. | **§1.6** (new), §1.4 |
| **Γ-F6** | Is the `kLatencyChanged` deactivate/reactivate acceptable as the cost of the toggle? | **Yes — ship dynamic latency as ruled.** No constant-latency fallback, no measurement gate. *Corrected this doc's analysis: the cost is self-inflicted, not SDK-imposed.* | **§3.1.1** (rewritten), §7.10, §7.11, `docs/TODO.md` |
| **Γ-F7** | VST3 parameter ORDER: signal flow, or the editor's visual rows? | **Signal flow***"signal flow order."* The frozen id numbering and the presentation index both follow the deck's own rule; the visual layout is too mobile to freeze against. | **§8.3**; `parameter-automation.md` §6.4 (argument) and §6.2 (the 44-id table) |
@@ -1534,7 +1558,7 @@ ceiling into W1 (§4.3.1) and turned the Ξ ordering constraint into an owned co
1. **Item B splits: canvas early, arrangement late.** The window floor, the width budget it
derives from, and each group's row membership land in W1-T4 so every other UI track is
drawn, tested and judged at the final 1190 × 680 window. The two-row layout itself stays in
drawn, tested and judged at the final 1198 × 680 window. The two-row layout itself stays in
W3-T1, because it can only be measured once the final PITCH/RATE and MASTER descriptors
exist. The exact seam — what W1-T4 can assert, what it cannot, and what the editor looks
like in between — is in `docs/PLAN.md` at Γ-W1-T4.
+1 -1
View File
@@ -499,7 +499,7 @@ will eventually propose "fixing" that. The answer is that the two *cannot* both
forever, and only one of the two axes holds still:
> **The editor's visual layout has already moved twice** — Θ-W6-T1 grew the window floor
> 840 → 980, and Γ-W3-T1 takes it to 1190 and re-rows every group into two categorical rows
> 840 → 980, and Γ-W3-T1 takes it to 1198 and re-rows every group into two categorical rows
> with a double-height MASTER. Within-row order is decided by *width fitting*, not by meaning.
> **Binding a permanently-frozen id order to a demonstrably mobile layout guarantees the two
> drift apart** — and after the first drift the order is neither logical *nor* matching, which