User request live: right-hand index pinch fires breakdown instead of
relanceEvolve — SC default, generator default, web defaults, the 196
presets and the test pins all updated. relanceEvolve stays in the
assignable vocabulary.
User request live: more audible depth on the hand X/Y mods. All 1848
lHand/rHand X/Y bindings across the 84 presets raised from 0.40-0.50
to 0.70 (per-voice editable in the web UI as before).
Update globalActions in all 84 .matrix preset files from old
default to: [\fill, \doubleTime, \washReverb, \muteDrums,
\relanceEvolve, \halfTime, \next, \muteMelo].
Context: Task 1 wired fistThresh into the SC matrix engine (default
0.15); the generator was not yet emitting this field, so every
.matrix was missing it and the engine fell back to its hardcoded
default.
Approach: TDD — added a failing check to test_global_actions.py,
then edited to_sc so pinchHoldMs ends with a comma and fistThresh
0.15 follows as the last field before the closing paren.
Regenerated 84 presets twice for determinism.
Changes:
- generate_presets.py: pinchHoldMs now ends with comma; fistThresh
0.15 emitted as the final key in every preset's SC Event literal
- test_global_actions.py: EXPECT_FTH block checks to_sc output and
all 84 on-disk .matrix files
- *.matrix (84 files): regenerated with fistThresh field
Impact: all four gates green (GLOBALACT-PY, test_sections,
test_families, GLOBALACT SC); fistThresh is now a first-class
preset field readable at load time by ~matLoadFile.
Add top-level 'pinchHoldMs': 300 to every generated .matrix so the SC
engine (Task 2) reads it instead of its hardcoded default.
- generate_presets.py: globalSettings ends with ',' and
'pinchHoldMs': 300 is the last field before the closing ')'
- test_global_actions.py: EXPECT_PHMS check added (TDD red then green)
- 84 .matrix files regenerated (28 morceaux x intro/live/outro)
Expand globalActions from 4 to 8 slots:
[\fill, \drop, \breakdown, \evolve,
\muteDrums, \muteMelo, \washReverb, \next]
Drop openThresh/closeThresh from globalSettings (now
engine-side constants via Task 1). Regenerate all 84
.matrix files deterministically.
All gates: GLOBALACT-PY PASS, TEST PASS x2, GLOBALACT PASS
Context: Phase 2 Task 1 made the SC engine load a globalSettings Event
from .matrix files (openThresh/closeThresh/transientBars/breakdownKeep)
and default it when absent. Generator was not yet writing the field.
Approach: append globalSettings after globalActions in to_sc() return
string; extend test_global_actions.py with EXPECT_SET check against
both the to_sc sample and all 84 .matrix files on disk.
Changes:
- generate_presets.py: to_sc now ends with globalActions (comma) then
globalSettings Event with default values matching SC defaults
- test_global_actions.py: add EXPECT_SET literal + two check() calls
- *.matrix (84 files): each preset now carries the globalSettings field
Impact: every preset ships with openThresh/closeThresh/transientBars/
breakdownKeep defaults; SC engine reads them on load; no more implicit
fallback needed at runtime for any preset in the library.
Context: SC engine (Task 2) loads 'globalActions' from .matrix files
and defaults to [\fill, \drop, \evolve, \breakdown] when absent.
Generated presets did not write this field, causing implicit reliance
on the engine default.
Approach: extend to_sc() return string to include the globalActions
key so every preset explicitly carries the default mapping
(LH-open=fill, LH-closed=drop, RH-open=evolve, RH-closed=breakdown).
Changes:
- generate_presets.py: add 'globalActions' line in to_sc() return
- test_global_actions.py: new Python test verifying to_sc() output
and all 84 on-disk .matrix files carry the field
- 84 .matrix files: regenerated with globalActions field present
Impact: presets are self-documenting; SC engine reads the explicit
value rather than applying a silent default.
The live loop tiled the plateau into 4 identical blocks -- full but static.
LIVE_STYLE maps each morceau to a style group; LIVE_VAR holds per-style
profiles; _live_variation recolours active cells in some 16-bar blocks
(rhythmic 2/4, melodic 3 octave) and adds phrase-end fills (colour 6) so the
full loop breathes in a genre-appropriate way -- techno double-time hats +
fills, breaks snare rolls, ambient gentle bell octaves, etc. Active cells
only -> density unchanged, no voice dropped, no intro/breakdown back.
test_sections asserts the live still has no intro/breakdown AND varies (not
4 identical blocks). Regen 84 deterministic, VALIDATE 84/84 + DEFAULTS PASS.
Each morceau's _live section reused the standalone arc, which re-introduced
(near-empty intro -> rebuild -> plateau -> breakdown). Now make_live_continuous
tiles the plateau (P, bars 32-47) across all 64 bars: full groove from bar 0,
no intro ramp, no breakdown -- a clean loop the _intro builds to and the
_outro descends from. Applied post-apply_colors for the live section only via
to_sc(post=); intro/outro unchanged.
test_sections asserts the live is full-from-start + has no breakdown dip.
Regen 84 deterministic, VALIDATE 84/84 + DEFAULTS PASS, test_families PASS.
The SP-A default bound danse->gate on the fx and sweep voices, so the
action-head classifying the dancer as "danse" toggled those voices on/off
even with no fx/sweep cells in the grid -- poses triggering FX that the
user never placed. Pose->voice triggers are now opt-in (default_poses
returns []); continuous pose modulation (default_mods) is unchanged.
Updated test_default_mods.py + the validate_presets DEFAULTS assertion
(fx voicePoses now expected empty). Regenerated 84 presets. VALIDATE
84/84 + DEFAULTS PASS; test_families + test_sections PASS.
Wire the hand-authored families into the 84 presets and make the launcher
boot the live section.
Changes:
- patterns_for: strip the _intro/_live/_outro suffix before the
PRESET_FAMILY lookup, so all 84 section presets resolve to their
morceau's family.
- PRESET_FAMILY: retarget mel families to the new banks where they fit -
house (detroit/rave/trance/melodic/electro), psy (hypnotic/psytrance/
minimal), dub (dub_techno/melodic_deep), ambient (ambient_intro); drum
families now style ride/shaker/clap/perc per dfam.
- launch_concert.sh: MATRIX_PRESET default -> techno_drive_live.
Impact: genre presets now use the authored families. test_families PASS,
test_sections PASS, regen deterministic, VALIDATE PASS 84/84.
Hand-write the intro and outro arc for each of the 28 morceaux (56 new
independent arc functions). intro = voices enter across the 64 bars
(sparse->full, capped at the plateau with a light O lead-in into live);
outro = voices exit (full early, dropping out toward the break/outro).
Approach:
- one arc_intro_<m> / arc_outro_<m> per morceau, registered in
INTRO_ARCS/OUTRO_ARCS; composed from the primitive fill/hit grid API
over the I/B/R/D/P/K/O section codes.
- the 7 breaks morceaux share a _breaks_intro/_breaks_outro shape
parameterized per morceau (deviation from "fully independent" - flagged
for review).
- test_sections.py gate: intro builds, outro breaks down, live densest -
all 28 PASS.
Impact: 84 presets regenerated, VALIDATE PASS 84/84. Section feel is
shape-correct; musical review by ear pending.