xtc/docs/EDITING.md

115 lines
8.4 KiB
Markdown
Raw Normal View History

# Editing commands and undo (Phase 27 audit)
The control thread owns project edits and history. Audio plans are immutable
snapshots; widgets never pass editable project pointers into the callback.
Graph commands and batch note commands use the existing public C command APIs.
The GUI groups a completed gesture or accepted dialog as one history step.
## Operation audit
| Operation | History / grouping | Engine and external effects |
| --- | --- | --- |
| Track create/delete/name/order; clip create/delete/move/trim/name | One accepted command/drag | Stops playback before mutation; track removal cascades clips/notes/lanes, never files |
| MIDI clip creation and default source routing | One command, including automatic route | Core candidate graph is validated before model adoption |
| Audio duplicate/split/gain/fades | One command including copied metadata/notes | Source WAV is shared; split does not rewrite samples |
| Note add/delete/drag/resize, filtered quantize/transpose/properties/repeat | One gesture/batch, including fresh note IDs | Stops playback; validates all matched notes/capacity before applying |
| Graph add/remove/connect/disconnect/insert gain | One graph command | Candidate and history storage prepared before engine submission; active graph remains immutable |
| Mixer gain/pan/mute/solo, bus create/route, automation points | One released slider/command/point | Stops playback; bus deletion reroutes members without deleting their media |
| Plugin add/replace/control/reset/automation/insert | One accepted command/dialog including wiring | Candidate compiles before installation; old module instances retire on control thread |
| MIDI controller bindings | One channel-map command | Rebuilds immutable MIDI plan; no callback mutation |
| Import/relink audio | One accepted edit, including newly needed track/routes | Import candidate prepared before adoption; source media never copied/deleted by undo |
| Recording start/stop | Start has no document history step; completed take adds one | Undo removes take reference, never finalized WAV; failed add retains saved take for manual import |
| Save / Save As | No history step; retains existing history | Writes document; undo does not restore earlier on-disk file versions |
| New / Open | Fresh baseline after unsaved-change handling | Parse/prepare failure retains old document/history; engine may already be stopped/reset after preparation failure |
| Transport, panic, external connections/reconnect | Not document history | Undo does not reverse playback, live voices, device connections or capture side effects |
| Selection, tabs, snap/grid, zoom/scroll, node layout, meters/reset peaks | Session UI state, no history | No music or media changes |
No arbitrary cross-command grouping or automation recording mode is introduced.
An accepted no-op model edit can still consume a step. History holds 32 edits
plus a baseline; new accepted edits discard redo, and eviction drops the oldest
baseline. Monotonic ID high-water marks survive undo and branches. History is
session-only; restart/New/Open discards it.
## History ownership and failure boundary
`xtc_history_reserve` allocates one empty fixed-capacity project/graph snapshot
before an edit mutates the document or a candidate is submitted to the engine.
Failure aborts the command without changing history or dropping redo. The call
is idempotent: storage left by a rejected command is reused. It neither records
an edit nor moves the cursor. GUI arrangement/note/mixer guards reserve before
stopping playback; candidate graph/plugin/map/take paths reserve before
publication. File/media work and compilation can still fail before adoption.
The next `xtc_history_record` copies model arrays and the bounded 64-node/4096-
edge graph into reserved storage without allocating. Successful record takes
ownership of that storage, remembers IDs, then releases old redo/evicted states.
The snapshot contains metadata/graph configuration only, never sample buffers,
DSP instances, module handles or GUI pointers. An unused reservation is freed
with history. This adds at most one pending metadata snapshot to the 33 retained
states. C clients that call record without reserving retain the original
clone-and-report-allocation-failure behavior; they must handle that result.
All history work is serialized on the control thread, never the audio callback.
Undo/redo checks out an owned candidate without moving the cursor, stops/resets
transport and prepares its assets/plans, then accepts the adjacent history step
only after installation succeeds. Failed checkout/preparation retains the
cursor/document, so retry is possible. Preparation failure may leave transport
stopped at zero; it does not resume playback automatically. Snapshot restoration
marks the document dirty conservatively, even if it matches a saved file.
## Selection, focus and menus
Ctrl+Z undoes; Ctrl+Shift+Z and Ctrl+Y redo. The main Edit menu disables unavailable
steps and disables history while recording. Piano roll also has Edit/Undo/Redo
shortcuts. Undo preserves currently selected track/clip, mixer strip, graph node
and piano-roll clip/note when their stable IDs still exist (notes must remain
visible under the current filter). Clip selection follows its restored track. A removed selection
clears, with track fallback for a removed clip. A visible piano roll stays open
when its clip survives; missing clips hide it. Historical selections/layouts are
not saved in snapshots; undo does not resurrect a selection already cleared by
a deletion. Open/New retain their reset behavior.
Editor-local shortcuts act on focused editors. Text inputs retain Space and
text undo/editing keys; numeric mixer inputs do not invoke fader shortcuts.
Timeline Ctrl+D duplicates, F2 renames, Alt+Up/Down reorders tracks, S splits
audio at the cursor, A opens audio properties and Delete removes the selection.
Graph Left/Right chooses a node, L arranges by flow, I inserts unity gain in the
selected wire, Delete removes the selected node/wire and Escape cancels gestures.
Piano-roll commands are listed in its Notes menu. Escape cancels gestures;
ordinary deletion is reversible and does not add a confirmation dialog.
Graph right-click now selects the node/wire under the pointer before showing
Inspect/Arrange/Insert/Delete; empty space clears a stale selection. Piano-roll
right-click selects the clicked note and offers Properties/Quantize/Repeat/Delete.
It no longer immediately deletes the note. Timeline context menus retain their
selection and duplicate/rename/delete/audio commands. Dismissing a context menu
does not edit the document. Context menus and widgets remain C++/FLTK UI code.
Open/import/plugin load/replacement paint a busy cursor and operation status
before synchronous work, flushing drawing without dispatching new input or
reentering commands. This is feedback, not background loading or cancellable
progress. Failure messages distinguish capacity, memory, target/value, format/
optional-support and audio errors. Unsaved New/Open/Quit and Save As overwrite
keep their existing confirmations; undoable deletes and external-media reference
edits do not request extra approval. No operation here deletes source media.
## Evidence and manual procedure
`make all test gui test-gui-plugins test-reliability analyze test-workflow
test-gui-jack` covers core commands, grouped gestures/batches, backend rollback,
selection retention, take undo/redo and real software JACK state restoration.
The GUI fixture injects history-reservation failure before graph/map/import
publication and verifies unchanged document, submission count and redo. The
allocation-interposed reliability suite fails each reservation allocation, then
fails all allocations while capturing a reserved edit; redo branching and
snapshot restoration still succeed. ASan/UBSan cover the same ownership paths.
For native manual inspection: right-click different graph nodes/wires and empty
space, dismiss the menu, and confirm only selection changes. Right-click a note,
dismiss, then explicitly Delete and undo; confirm the note returns. Type spaces
and use text undo in a name/input dialog, and edit numeric mixer fields without
triggering fader keys. Record a short take, stop, undo once and confirm its WAV
still exists; redo restores the reference. Watch operation feedback on a large
import/Open. These manual popup/focus/large-file and physical-device listening
checks remain pending; automation does not claim broad accessibility or human
usability qualification. Existing native-plugin failure limits still apply.