115 lines
8.4 KiB
Markdown
115 lines
8.4 KiB
Markdown
# 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.
|