xtc/docs/GUI.md

262 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# GUI Guidelines
Use FLTK/C++ for windows, menus, dialogs, and the event loop. Keep all audio
engine and project-domain logic in C.
Main views:
- Sequencer: tracks, clips, ruler, playhead, selection, zoom and scrolling.
- Mixer: channels, faders, pan, mute/solo and meters.
- Modular graph: nodes, ports, connections, validation feedback.
- Transport: play/stop/record, tempo, meter, loop and position.
Use custom-drawn widgets where ordinary controls are not a good fit: timeline,
waveforms, piano roll, mixer strips and graph canvas. Keep drawing separate from
project mutation. Never call FLTK from the audio thread.
Visual direction: compact, high-contrast, restrained dark interface. Avoid
excessive animation and modal configuration. Recreate broad usability ideas, not
energyXT's exact artwork or proprietary resources.
---
## Shell
The shell opens JACK on startup through `xtc_backend.h`. It never accesses
backend structures, processes samples, or calls JACK itself. Graph domain data
is owned by opaque C objects, manipulated only through the C API. All backend
control calls run on the GUI thread; FLTK is never called from an audio
callback. No server is started and no audio ports are connected by the GUI. The
initially empty graph produces silence.
- **Play / F5:** start the engine. **Stop / F8:** deactivate it. **Pause / F7:**
hold playback. **Space:** toggle Play/Stop. **To start / Home:** stop and seek
to zero. Pause/Home are disabled while recording. These advance/pause the
sample-counted playhead; imported audio clips play through their graph source.
- **Reconnect / F6:** close the old client and open a fresh stopped client. Use
this after server loss or sample-rate changes. A failed close preserves the
handle and reports the failure instead of opening another client.
- **View menu / Ctrl+1, Ctrl+2, Ctrl+3:** switch between sequencer, mixer and
modular graph. Tabs provide the same view switching. Mixer, graph and
sequencer editors are described below.
- **File / Quit / Ctrl+Q** or the window close button: close the backend and
synchronize audio callbacks before hiding/destroying widgets. A failed close
leaves the window open for a retry. New/Open/Save actions are described below.
About identifies the development milestone and version.
The indicator shows disconnected, ready, running, server lost, format changed or
process-error states. The status line shows rate, actual block size, mono
layout, processed block count, xruns and process result. Command errors remain
visible until a successful control action; periodic refresh does not erase them.
A GUI-owned 100 ms timer reads atomic snapshots and collects retired plans.
Label text changes only when needed. The timer is removed before successful
close and again by the window destructor. No GUI locks are held across control
calls. Operations such as opening JACK can briefly block the GUI; there is no
worker/control-thread framework in this initial shell.
MainWindow owns the backend handle and FLTK owns the window's children. The
destructor also attempts cleanup on exceptional event-loop exit; if JACK close
itself fails then, it reports to stderr and retains the callback context until
process exit. Normal close/reconnect paths permit retry and release ownership
only after successful close. The entry point catches C++ exceptions before
process exit. Backend operations return C error codes throughout.
Tests: `cmake --build build --target test-gui` runs real widgets/callbacks/timers against a fake C
backend under Xvfb, including control errors, startup without JACK, partially
initialized handles, server/format notifications, view switching, retrying
close, and timer removal. `cmake -S . -B build -DXTC_ENABLE_LIVE_TESTS=ON && cmake --build build --target test-gui-jack` additionally requires a running
JACK-compatible server, tests repeated start/stop, reconnect and active-client
close, and creates no routes. Physical playback is outside this shell. See
BUILD.md and the integration test README for sanitizer limitations and keyboard
smoke results.
---
## Modular Editor
Open **Modular Graph** or press **Ctrl+3**. Add oscillator (440 Hz), gain
(0.10), pass-through meter or output nodes with the toolbar. Their parameters
are fixed presets in this milestone and are drawn on each node; parameter
editing and live meter display are not implemented. Connect oscillator → gain →
meter → output for a simple test chain. No sound reaches hardware until ports
are explicitly connected outside the GUI. Output nodes are required to render;
isolated sources and an empty graph produce silence.
Drag a node body/title to move it. Drag a circular output port to an input port
to connect. Click a node or wire to select it (yellow outline/wire), then press
Delete/Backspace or **Delete selection**. Deleting a node deletes its incident
wires. Escape cancels a drag preview. Canvas scrollbars pan the view; positions
are retained across edits/reconnect but not across application restart. There is
no graph zoom, multiselection or external hardware routing UI. Semantic graph
edits participate in project undo/redo; layout does not. The default project
supports 64 nodes; auto-layout can grow the scrollable canvas.
Every semantic action becomes a C graph command. The window owns a C project
containing the graph handle and publishes the C-created candidate through the
backend. Cycle, invalid-direction, duplicate connection, missing-port, capacity
and backend failures are shown below the canvas; failed edits leave the graph
unchanged. Capacity feedback distinguishes the possible node limit/pending edit
condition and allows retry. Editing while stopped replaces the prepared plan
without starting playback. Editing with a disconnected startup backend stays
local until reconnect. A lost or changed live backend requires reconnect before
further semantic edits. Moving/selecting nodes does not touch the engine.
The graph state line distinguishes offline, prepared, queued and active states.
Queued explicitly means the drawing represents the next submitted graph while
the engine finishes the previous plan. The 100 ms GUI timer observes audio
adoption revisions and then shows active. Graphs are not edited in place on the
audio thread. There is no automatic retry/hidden edit queue; users retry a
rejected capacity edit. Plan replacement can reset oscillator phase and is not
crossfaded. Render validation and active replacement tests are described in
tests/integration/README.md.
---
## Projects and Sequencer
File/New (Ctrl+N), Open (Ctrl+O), Save (Ctrl+S), and Save As (Ctrl+Shift+S) use
native file dialogs and the C persistence API. New/Open/Quit offer
Cancel/Discard when semantic edits are unsaved; save first to retain them. Save
As confirms overwrites. The title marks unsaved changes. Failed loads and
backend submissions retain the old document. Loading parses before stopping
audio; installing a valid candidate stops and resets transport before compiling
and submitting. A later failure can leave the retained document stopped at zero.
Opening/New resets graph layout; graph positions are not saved. See
PROJECT_FORMAT.md.
Sequencer offers Add track, Add region, Delete region/track, Zoom +/-. Select a
track header to add a one-bar region there at the cursor. Select a region to
delete it; deleting a selected track cascades to its regions. Delete also works
with canvas focus. Drag a region body to move it in time or between tracks; drag
either edge to trim within its original source bounds. Edits commit on release
with the selected snap grid; Escape cancels. There is no drag preview. Undo,
rename, tempo editing and additive clip selection are supported. Group commands,
clipboard and musical transforms are described in
[MODERN_EDITING.md](MODERN_EDITING.md). Overlapping regions are permitted.
The scrollable canvas expands to cover the arrangement plus a margin; zoom
ranges from 24 to 384 pixels/quarter. Names, tempo and 4/4 meter are drawn. A
ruler click seeks while stopped (or positions the cursor when disconnected). The
100 ms GUI refresh converts the backend's actual sample counter to ticks; it
never integrates wall-clock time. Play resumes and Stop pauses. Reconnect, New
and Open reset position. Add region creates silent metadata; imported WAV clips
play through the audio source node (see below). MIDI clips and notes are
described below. The C model supports a constant tempo; a tempo map and
scheduler are future work.
Tests cover C-model/persistence boundaries, GUI move/trim gestures and zoom,
save/reopen, failed load/submission rollback, sample-derived cursor updates, and
live JACK playhead advance/pause.
### Sequencer components
The sequencer is a master `Fl_Group` containing a ruler and one group per track.
Each track contains clip widgets, a velocity lane, and a pinned header group
with its instrument selector. Local drawing and input live with those children;
the master coordinates selection, scrolling, zoom and cross-track edits.
See [widget ownership and source files](ARCHITECTURE.md#sequencer-widget-ownership)
for the implementation map and lifetime rules.
Click the small track-header arrow to expand a track downward. MIDI tracks
expose note velocity bars (1–127); drag a cap to edit a note. Audio tracks expose
the saved track-gain envelope (0–400%): click at any timeline position to add a
point, drag vertically to adjust it, or right-click a cap to remove it. Audio
positions ignore the snap grid. Escape cancels a preview; undo/redo restores
committed edits. Instrument selectors retain their own keyboard focus.
Expansion is temporary view state; audio gain points are shared with the mixer
and saved with the project. This component refactor preserves the existing
workflow and project format.
---
## Audio Workflow
Use File/Import WAV (Ctrl+I) to add an audio clip at the playhead on the
selected track, or on a new Audio track. Record (Shift+F5) chooses a WAV
destination and captures JACK input until Stop finalizes and adds the take. No
input routes are created automatically. Save after Stop; the project references
the external WAV.
Import creates an Audio clips graph source and output route if the source is
absent. Modular Graph offers Add audio source for explicit routing through gain
or meter nodes. All tracks currently share one mono timeline mix. Arrangement
edits stop playback; graph edits remain live outside recording. During
recording, edits, file actions, reconnect and close require Stop first.
Open/Play reports missing, unreadable or unsupported assets, preserving their
regions as silence. The backend status shows the unique issue count. Select a
clip and use File/Relink selected audio to choose another path; Play validates
the replacement. Playback uses preloaded immutable samples; imports and loads
can block the GUI while reading, but never the audio callback.
See AUDIO_FILES.md for supported WAV formats, memory limits, musical placement,
recording overflow/partial-take recovery, external asset portability and the
software-only acceptance tests. Waveform drawing, input monitoring, recording
latency compensation and per-track graph inserts are not implemented. Per-track
gain/pan/mute/solo is available in the mixer below.
---
## Piano Roll
Add MIDI clip creates a one-bar clip on the selected/first existing track at the
cursor. Select it and choose Piano roll (View/Piano roll, Ctrl+4). Click to
draw, drag a body to move pitch/time, drag its right edge to resize, and
right-click or Delete to remove. Notes use source ticks with 1/16 snapping;
trimmed source content is retained. Edits stop transport and are blocked during
audio recording. Panic/F9 silences held notes; Record continues to mean WAV
audio capture. Modular Graph offers Add instrument for explicit routing. Status
includes MIDI drops. See MIDI.md for voice limits, unsupported messages and live
input routing.
---
## Mixer and Editing
Mixer (Ctrl+2) now has a selectable track strip, gain/pan controls, mute/solo,
Output L/R peaks and editable gain/pan automation lanes. Mixer edits stop
playback. Click the lane to add/replace points, right-click near a point to
remove, and change First tick to navigate. Ctrl+Z, Ctrl+Shift+Z and Ctrl+Y undo
and redo up to 32 project edits; New/Open resets history. M/S and arrow keys
provide mixer shortcuts. See MIXER.md for exact controls, history rollback,
stereo port routing, automation semantics and prototype limits.
---
## Minimal Composition Workflow
[WORKFLOW.md](WORKFLOW.md) walks through creating, arranging, saving, closing,
reopening and playing MIDI/audio with the GUI. New/Open select Sequencer; Ctrl+3
still opens the modular graph. Stop retains its established position-hold
behavior and finalizes recording; explicit Pause retains position without
finalizing a take (and is refused during recording). Home stops and returns to
zero. Failed candidate installation now refreshes the actual backend state even
when the previous document is retained.
`cmake -S . -B build -DXTC_ENABLE_LIVE_TESTS=ON && cmake --build build --target test-workflow` uses a live JACK-compatible backend and Xvfb, with exact
stereo render comparisons across destruction/recreation of the GUI and live
playhead/meter/transport checks. `test-gui` covers stop/seek failure and
recording guards. No project files need manual editing for this workflow.
---
## Timing and Transitions
The GUI enables 5 ms source boundaries and master start/stop ramps. Ordinary
Pause/Stop now request a fade and show “stopping” until the timer collects its
acknowledgement and deactivates JACK. Recording Stop, Home, fault handling and
project installation retain immediate semantics. See
[AUDIO_QUALITY.md](AUDIO_QUALITY.md) for timing, overload/denormal behavior,
latency limits, test commands and the pending human-listening checklist.
---
## Routing Refinement
Graph selection now reports edge counts, output reachability and external-input
fallback. Direction arrows, role colors, incident-wire highlighting and
no-output badges help inspect routes. View / Arrange graph by signal flow (L) is
a layout command; Edit / Insert unity gain in selected wire (I) is one undoable
graph edit. Left/Right selects nodes; Tab retains ordinary focus navigation. See
[ROUTING.md](ROUTING.md) for summing, stereo-lane, cycle, live publication and
deferred grouping/template semantics.