Pre-c3b51bc sompyler emits offset.stem_note/motif.stem_note/clause.note
while new sompyler emits line.stem_note/seq.note. Parser now accepts both
parentSlot values for stem_note, motif, and clause children so the app
works against both old and updated sompyler installations.
Also falls back to reading chain.clause directly from stem_note's children
when no stem_note.chain node is present (old format had no chain wrapper).
Sompyler commit c3b51bc renamed slots across the board:
- offset.stem_note → line.stem_note (parentSlot 'offset' → 'line')
- motif.stem_note → line.stem_note (parentSlot 'motif' → 'line')
- clause.note/pause/stack → seq.note/pause/stack (parentSlot 'clause' → 'seq')
- stem_note.chain is now a real hierarchical node (depth 04) between
line.stem_note and chain.clause; clauses are now its children, not
direct children of stem_note
Also adds:
- offset.motifs[] for line.motif invocations at tick positions
- stem_note.writeToName from stem_note.write_to positional
- adjacent prop already stored; new tests verify True/False/absent
PaneFO.js: show offset motif invocations inline (label + chord)
test-parser.mjs: update synthetic fixtures to new depths/slot names;
add tests for line.motif, stem_note.write_to, adjacent prop
- ast-parser: read for_value= prop for sub-variations (was always null,
causing fallback to positional "subvariation N" label)
- StatusPoller: calculate progress from currently_rendered_notes /
notes_in_total; show remaining_time string from status.json
- ShapeEditor/EnvelopeEditor: pass { undo } through onChange so callers
can revert in-place mutations
- PaneFO: makeChangeHandler stashes undo from info arg; discardEdit
calls undo() before clearing pendingEdit; depends_on handler provides
its own undo for the inline node.dependsOn mutation