243 lines
13 KiB
Markdown
243 lines
13 KiB
Markdown
# 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.
|
|
|
|
---
|
|
|
|
## 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.
|